Like many of you, I write a lot of PowerShell code. Much of it I use on a daily basis since I essentially spend my day at a PowerShell prompt. Also like many of you, I often assemble functions into a module. A module makes it easier to load the functions I need, and also provides a versioning mechanism. When I run Get-Command on a module function, I can see the module name and the loaded version. But, there is more to my PowerShell life than modules. I have a number of stand-alone functions that I rely on. Many of these are dot-sourced in my PowerShell profile scripts. I know I am not the only PowerShell professional that relies on stand-alone PowerShell functions. The challenge, at least from my perspective, is that there is no versioning mechanism. There's no way to get similar information about a stand-alone function when I run Get-Command. That's the problem I wanted to solve.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
PSFunctionInfo
Over the last year, I've been working on a solution. I've been using it and finding it helpful. My friend Gladys Kravitz was also bemoaning the lack of tools for managing stand-alone functions. And while she had her own approach, I thought my solution might offer more. So I polished it up, setup a Github repository, and published a preview release to the PowerShell Gallery. The module is called PSFunctionInfo. You can find the repository on Github. Because it is a pre-release, you might need to install the newest version of the PowerShellGet module so you have the prerelease parameters.
Install-Module PSFunctionInfo -AllowPrerelease
Function Metadata
The module works around the idea of a metadata comment block inserted into the function definition. It looks like this:
Function New-GHIssue {
<# PSFunctionInfo
Version 1.1.0
Author Jeffery Hicks
CompanyName JDH IT Solutions, Inc.
Copyright (c) JDH IT Solutions, Inc.
Description Create a Github issue using gh.exe
Guid 99b832ff-f003-4394-baca-7043b1f13ab2
Tags github,profile
LastUpdate 4/22/2021 8:56 AM
Source C:\Scripts\New-GHIssue.ps1
#>
[cmdletbinding(SupportsShouldProcess)]
Param(
...
The module command Get-PSFunctionInfo will process all functions loaded into your PowerShell session and show you your stand-alone functions. This is the default view.
The module includes a custom format file with an additional named view.
I tried to design a rich object so I would have flexibility when it came to searching or examining a function.
Adding PSFunctionInfo
While getting information works on loaded functions, adding function metadata must update the source .ps1 file. The command you'll use is New-PSFunctionInfo.
New-PSFunctionInfo -Name Show-WeatherSummary -Path C:\scripts\show-weathersummary.ps1 -Tags profile,web -Author "Jeff Hicks" -CompanyName "JDH IT Solutions, Inc." -Copyright "(c) 2021 JDH IT Solutions, Inc" -Description "display weather snapshot" -Version "1.0.0" -Verbose
I used all the parameters, even though some of them have default values. You can see the metadata that will be inserted. Note that this *will* update the ps1 file.
Limitations
There are a few limitations. First, the command will not work with a one-line function declaration like this:
Function Get-Noun {Get-Command -CommandType Function,Cmdlet | group noun -NoElement | sort count -Descending }
The function should look like one of these:
Function Get-Noun {
Param()
Get-Command -CommandType Function,Cmdlet |
Group noun -NoElement | sort count -Descending
}
Function Get-Noun
{
Param()
Get-Command -CommandType Function,Cmdlet |
Group noun -NoElement | sort count -Descending
}
It also assumed that you don't have multiple copies of the same function in the same .ps1 file. I'm working on the assumption that the stand-alone functions you want to manage a slightly more complex than a few lines of code.
Editing PSFunctionInfo Metadata
The current version of the module has no commands to edit, update, or remove function meta data from the file. I'm expecting that if you are editing the function, you can revise the metadata block at the same time. Be careful not to adjust the spacing or formatting of the comment block. I tried several approaches and decided the multi-line comment block struck the right balance between ease of use and management.
PSFunctionInfoDefaults
Finally, even though New-PSFunctionInfo has a few default parameter values, since you might want to maintain some consistency in your function metadata, the module includes a few commands for managing default values. You can run Set-PSFunctionInfoDefaults to specify metadata defaults like Author and Company. The command will create a JSON file under $Home called psfunctioninfo-defaults.json. When you import the PSFunctionInfo module, if this file is found, it will be imported and used to set entries in $PSDefaultParameterValues.
You can set new defaults at any time. Use Get-PSFunctionInfoDefaults to view your settings. If you make a change, you can either re-import the module or run Update-PSFunctionInfoDefaults to refresh $PSDefaultParameterValues. If you uninstall the module, you'll need to manually delete the JSON file.
Do You Need This?
If this looks like something you need, I hope you'll install the module and give it a try. I'd suggest you have a backup of any files you intend to modify. Of course, being the pro that you are that should be a given! Please use the Github Issues section of the repository to post any comments, bugs, or feature requests. I'm hoping to get some real-world feedback before I remove the prelease tag. Thanks in advance for your help.
Why don’t you generate modules from that ps1 files instead? Than get-command – module xyz would tell you what your functions are. And it is much faster to load module instead of ps1 files.. I use this approach in my solution https://github.com/ztrhgf/Powershell_CICD_repository
Yes, I could create a generic module for stuff that doesn’t really belong together. But I shouldn’t be forced to. And I think it is silly to create a module for a single function.
You can automatically generate as many modules as you want. So you can separate functions by their purpose as you like. And than easily get functions just from these custom made modules :-). For example you can use https://doitpsway.com/automate-powershell-module-creation-the-smart-way
Anyway I have noticed that you are using regex to find the function definition etc. I would suggest using AST which is great for code analysis. Some examples are in the url above at the bottom of the article. It is much safer and bullet proof than regex 👍
I appreciate your feedback. The point is there will always be a need for stand-alone functions. At least the way I work. And I originally started with the AST. The challenge is that I need to insert my metadata comment block into the file and the AST can’t help with that. It can tell me about the code, but not the file it is stored in. I’m working on some updates that will use the AST, but not for creating.
I’m curious if install-script would help? It’s integrated into powershellget and designed for single scripts.
Thanks for the idea but I don’t think would help much First, I’d have to set up my own repository, which isn’t that difficult, but still a step. Plus, that doesn’t help if there are two functions in the same script file.