Write-FunctionCallToHost: a simple cross-platform PowerShell function wrapper
Summary
Since PowerShell Core was released in January (which means it's supported officially), it is now possible to run PowerShell on Windows, macOS and Linux. This means it has become a realistic scripting language to use in a lot more environments.
Not only that, submitting a module to the PowerShell Gallery is a lot easier than you might expect.
In this article we're going to submit a simple module to the PowerShell gallery and then install (and run) it on Windows, macOS and Linux machines. As usual, the code (what little there is) can be found in GitHub, although you don't need to download it from there as you can install it through PowerShell.
And, of course, I intend to use the specific function I've published (Write-FunctionCallToHost
) in some other scripts in the future.
And don't forget, it's all open source so, if you want to learn more, the main PowerShell GitHub repository is worth checking out.
Background
Ever since writing my first production PowerShell script in 2011[1], I've thought it was pretty cool. In my current contract role, I'm working as a DevOps engineer and my main work machine is a MacBook Pro (I know). Since this is the first time I've ever used a Mac in anger[2], I thought it was also the perfect time to have a look at PowerShell Core and see if it really is cross-platform.
Write-FunctionCallToHost
As part of a separate PowerShell script I'm going to release in a few days, I thought it would be handy to have a way to wrap function calls and to write them to the screen. The function itself is nice and short and this article is more about the process than the specific function.
Here is part of the script in question (with the full version being available at https://github.com/TomChantler/Write-FunctionCallToHost/blob/master/src/Write-FunctionCallToHost.psm1):
I have omitted the long, comment-based help which appears when you use the Get-Help
command (but it's in the linked file on GitHub). It's outside the scope of this article, but you can read (a lot) more about it here and you can use my script as a starting point to create your own.
The last line is quite important. Export-ModuleMember
is used to denote which functions are to be exported by the module. It's a good habit to specify these explicitly.
What does it do?
Write-FunctionCallToHost wraps a function call and emits a bit of text before and after making the call (and optionally suppresses any output generated by the called command). And that's it.
The best way to see what it does is to run PS> Get-Help Write-FunctionCallToHost -Help
, but let's not get ahead of ourselves.
How to publish a PowerShell Module to the PowerShell Gallery
It's really simple. Before you start, you need to make sure you've got the latest version of PowerShellGet
(which is linked from the homepage of https://powershellgallery.com). You want version 1.6.0 (or later) and you can check your version by running:
PS> Get-Module PowerShellGet
Once you've created your .psm1
module file similar to the above (which is very similar to an ordinary .ps1
file, with the addition of a call to Export-ModuleMember), you should create a .psd1
module manifest, which you can do automatically like this:
PS> New-ModuleManifest -Path 'C:\GitHub\Write-FunctionCallToHost\src\Write-FunctionCallToHost.psd1' -Author 'Tom Chantler' -CompanyName 'TomSSL' -RootModule '.\Write-FunctionCallToHost.psm1' -Description 'Write-FunctionCallToHost wraps an existing PowerShell function (or simple block of script) to give a more user-friendly output.'
You can edit the .psd1
file afterwards, so don't worry too much about getting it all right first time.
Now you need to choose where to publish it. I chose to publish mine to the PowerShell Gallery which required me to sign up and then to grab my API key.
You can publish it like this:
PS> Publish-Module -Name .\Write-FunctionCallToHost.psd1 -NuGetApiKey '<your api key taken from powershellgallery.com>'
You can find it in the PowerShell Gallery at https://www.powershellgallery.com/packages/Write-FunctionCallToHost/
Installing Write-FunctionCallToHost
You can install Write-FunctionCallToHost
by running the following command:
PS> Install-Module -Name Write-FunctionCallToHost
When you try to install a module from the PowerShell Gallery, it will warn you that the repository is untrusted and prompt you to decide whether or not to proceed. This makes perfect sense when you consider the fact that anybody can upload anything to the PSGallery without it being reviewed by Microsoft and thus it's possible that people might put malicious stuff in there, or just stuff that doesn't work properly. If you like, you can tell PowerShell to trust this repository, but based on what I've just written, that doesn't feel like a very good idea.
There are a couple of ways around this issue.
You can either allow the user interaction and just say Yes
when prompted to install the module, or you can add the -Force
flag like this:
PS> Install-Module -Name Write-FunctionCallToHost -Force
Here is a cool animated gif I made which shows the installation on Windows.
If you want to fund out how to use the function, you can use the interactive help.
PS> Get-Help Write-FunctionCallToHost
PS> Get-Help Write-FunctionCallToHost -Example
PS> Get-Help Write-FunctionCallToHost -Online
Pay particular attention to the last one (with the -Online
flag). That will bring you here (to this blog post, which also links you to the GitHub repository).
As usual, the code is in GitHub: https://github.com/TomChantler/Write-FunctionCallToHost
And, just for a more complete view, here is what it looks like on MacOS (installation and then showing the interactive help):
Testing the function
Let's test the function by using it to wrap a simple call to my blog and then optionally suppressing the output. The following command is fairly self-explanatory:
Write-FunctionCallToHost -FunctionToCall { (iwr https://tomssl.com).Links.Count } -InitialMessage "I'm going to load Tom's blog and count the links" -FinalMessage "I've loaded it and counted them" -SuppressOutput $false
This is what it looks like on Windows 10:
This is what it looks like on MacOS (I had to recapture this image a day later than the others, hence the number of links being 63):
This is what it looks like on Linux:
Success.
IMPORTANT NOTE: Right now, the installation process doesn't seem to work properly on Ubuntu 16.04. In the end it appears to be related to a problem whereby the
-ExcludeVersion
flag doesn't work inPowerShellGet
.In brief, instead of being able to install my module via
PS> Install-Module -Name WriteFunctionCallToHost
(which failed silently), I had to do the following:
How I installed Write-FunctionCallToHost on Ubuntu 16.04 LTS
PS> Install-Package -Provider NuGet -Source https://www.powershellgallery.com/api/v2 -Name Write-FunctionCallToHost -Destination '/tmp/' -Verbose -Debug
PS> Test-ModuleManifest -Path /tmp/Write-FunctionCallToHost.1.0.0/Write-FunctionCallToHost -Verbose
PS> Import-Module /tmp/Write-FunctionCallToHost.1.0.0/Write-FunctionCallToHost -Verbose
Conclusion
As we have seen, submitting a PowerShell module to the PowerShell Gallery (or, indeed, any other PowerShell repository) is very easy to do. And having done so, installing it on either Windows, macOS or Linux[3] is also simple. If you're targeting various different types of environments and haven't already tried PowerShell, it might be time to take a look.
You can find Write-FunctionCallToHost in GitHub and also in the PowerShell Gallery and you can install it via
PS> Install-Module -Name Write-FunctionCallToHost
It ran a SQL script, produced a CSV and then emailed it to a bunch of people and was a replacement for a load of VBScript inside a SQL DTS module. ↩︎
Not as much anger as you might think; I'm super-chilled since reading the stoics. ↩︎
With the exception of Linux, it would seem. Or maybe just Ubuntu 16.04. It's still possible, mind you. ↩︎