Unable to create a PowerShell alias in a script module - powershell

Steps to reproduce:
Create a TestAlias module in \WindowsPowerShell\Modules\TestAlias\TestAlias.psm1 with the following function and alias:
function foo
{ write-output 'foo' }
New-Alias -name bar -value foo
From a PowerShell session:
import-module TestAlias
bar
The term 'bar' is not recognized as the name of a cmdlet, function, script file, or operable program...

You can use
Export-ModuleMember -Function * -Alias *
to export all functions and aliases.
By default, Windows PowerShell modules only export commands (functions or cmdletS), and not variables or aliases.
I'll go into a little more detail about why this is.
The short answers is that aliases, while convenient when writing one liners, are a barrier to understanding a script or a module. They are icing on the cake of a good cmdlet, but the core thing to expose is the good cmdlet. Aliases make it more difficult for a user reading your script to figure out what you're trying to do (Set-Content is a lot easier to understand than sc). Variables can be even worse to expose, as they can easily be set to unexpected values and as there is very little to help a user of your module figure out that they are there. Because commands are easily discoverable (Get-Command -Module FOO) and easier to explore (with Get-Help), the default that a module will export is only commands. As with most other things in PowerShell, you can override it if you choose, but by default commands are the only thing that are exported from a module.
Hope this Helps

Use Export-ModuleMember in the PSM1 file to export the Alias
Export-ModuleMember -function foo -Alias bar

Related

Can I hide a definition from Import-Module?

I have a file with a group of function definitions and variable assignments, some of which are only used to help other functions or definitions. Is it possible to hide these from the Import-Module command such that the user cannot see them?
Alternatively, is there a method for manually declaring exports?
It seems you haven't been exporting your module members manually. Use the Export-ModuleMember Cmdlet to do so. If you do not export a member, it won't be seen by the user.
To export a function/cmdlet/alias/variable, write
Export-ModuleMember -Function MyFunction -Alias MyAlias -Cmdlet MyCmdlet -Variable MyVariable
at the bottom of your module file.

Does PowerShell import function as module command by naming convention?

I have a PS module and in the .psm1 file for this module all relevant .ps1 files are "dot-sourced", or in my vocabulary: loaded. In one of the .ps1 files, let us say I have a function SetFoo.
If I do an Import-Module I cannot use the SetFoo function. If I list the commands for the module via Get-Command it is not available.
If I change the name of the function to Set-Foo the function is recognized after having done Import-Module and it is listed via Get-Command.
So my question is: is it via function naming convention that Set-Foo is loaded and SetFoo is not? I have googled myself silly, but cannot find anything in the PS docs about this.

How to expose sub module function, from a module

How do you expose a function and an alias from a module, from a sub module
profile.ps1:
Import-Module module_one.psm1
module_one.psm1:
Import-Module module_two.psm1:
module_two.psm1:
Set-Alias readme -Value "Read-Me"
function Read-Me() {
Write-Host "Hello..."
}
Export-ModuleMember -Function Read-Me, readme
I want to be able to call this function from the pwsh terminal, function name or alias?
I get (readme or Read-Me):
Read-Me : The term 'Read-Me' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the name,
or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ co
+ ~~
+ CategoryInfo : ObjectNotFound: (co:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Note: it works for functions in module_one.psm1.
Assuming that you call Import-Module module_one.psm1 and later readme / Read-Me in the same scope domain (either outside a module or from the same (other) module), your code works in principle:
The exported elements of the indirectly imported module are (also) imported into the top scope of the caller's scope domain.
Your problem is that you're trying to export alias readme as a function; you need to use the separate -Alias parameter instead:
Export-ModuleMember -Function Read-Me -Alias readme # Note the -Alias parameter
Also note that in the absence of an Export-ModuleMember call it is all (top-level) functions and aliases (but not variables) that are exported by default, so in your particular case simply omitting the call would have fixed the problem too.
In general, though, it is better to be explicit about what elements are exported, and that is best done via a full-fledged module that is not just a single *.psm1 file, but an entire directory named for the module, housing the *.psm1 file with an associated module manifest, which is a *.psd1 file that describes the module, notably also in terms of its exports.
If such a module is placed in one of the directories listed in $env:PSModulePath, its exported commands can be discovered (e.g., with Get-Command or tab-completion) even before the module is imported, via a feature called auto-loading - see about_Modules.
Note that Import-Module -Global is rarely needed and should generally be avoided, because it makes a module's exported elements available to all loaded modules too, which can have unintended side effects (modules should declare their dependencies explicitly).

Exporting PS Members from Module Fails

I have a psm1 module with several functions. I only want to expose some of the functions, so I used "Export-ModuleMember -Function " and everything was fine.
Now I want to add a manifest, so I removed the Export-ModuleMember cmdlet and put the function names under the FunctionsToExport section of the psd1 file.
When I import the module, I can tab-complete the functions, but when I try to use them, ps says:
Test-Function : The term 'Test-Function' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
I also tried putting Export-ModuleMember -Function * into the psm1, but that didn't help.
The psm1 and psd1 files are named the same and are in the root of the module.
Thoughts? Thanks.
I found the answer. I had forgotten to un-comment the RooteModule node. Once I did that (and had module.psm1 as the value), the exported commands showed up in the "Get-Module module" output.
I would suspect that PowerShell caching mechanism is involved here. Try to run:
Get-Module -ListAvailable -Refresh
I recommend very good article on that subject written by PowerShell MVP Tobias Weltner.

Is module auto-loading meant to be reliable?

Environment
I have the following folder structure where I keep powershell modules:
C:
PsModules
...
util
util.psm1 (this contains implementation of 'Test-Function')
util.test.ps1
ftp
ftp.psm1
http.test.ps1
...
There are about 50 folders and modules in c:\PsModules.
I have set environment variable PSModulePath to include c:\PsModules. This seems to meet the conditions for "well-formed modules" described in Microsoft's documentation and this answer.
Symptoms
Sometimes Test-Function is not found automatically when calling it from ISE. In fact, on any given fresh launch of ISE, there are always some (seemlingly unpredictable) modules that are not found automatically. The failure to automatically find Test-Function, for example, looks like this:
PS C:\> Test-Function
Test-Function : The term 'Test-Function' is not recognized as the name
of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is
correct and try again.
...
+ FullyQualifiedErrorId : CommandNotFoundException
At first glance, this seems to indicate that util.psm1 is not "well-formed". If it were not "well-formed", then ListAvailable shouldn't work. But it does work:
c:\> get-module -ListAvailable util
Directory: c:\PsModules\util
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0 util
PS C:\> Test-Function
...
+ FullyQualifiedErrorId : CommandNotFoundException
Furthermore, after calling Get-Command for the module, the commands in the module are available for general use:
c:\> Get-Command -Module util
CommandType Name ModuleName
----------- ---- ----------
Function Test-Function util
c:\> Test-Function
Call to Test-Function succeeded!
Questions
Is automatic discovery and module auto-loading supposed to be reliable and predictable?
How do I troubleshoot why powershell is sometimes doesn't find a command until a call to Get-Command -module?
Is it bad practice to rely on powershell to automatically load modules? If so, what is the good practice for automatically loading modules?
I can't speak to whether module auto-loading is intended to be reliable, but I personally do not rely on it in finished code.
If I'm writing a script or module, I always use Import-Module TheModule -ErrorAction Stop, and often use #Requires -Module AciveDirectory,TheModule,SQLPs to ensure that the modules are available.
For interactive use in the PowerShell console or ISE, I do generally rely on auto-loading, but if it fails I just Import-Module manually for the session.
In situations where I always want a specific module loaded for an interactive session, I load it in a profile. To see the various profiles run this (from both ISE and Console):
$profile | Get-Member -MemberType NoteProperty
You can decide where you want to place the code for importing the module based on which user(s) and in which host(s) you want the module to be available.
So far I only do this for posh-git, but it seems like it would fit your use case well.
In case this is helpful to anyone else, I think this may be a problem exclusive to ISE. I could not repro but recently went around with MS on inconsistent ISE workflow behavior and after some effort the issue was closed without a solution, with the official answer being to not use ISE which is not approved for production and instead use the native shell. It was a realistic answer for us, never saw the issues in native shell. I wonder if it's the same on this symptom?
I have found that the FunctionsToExport section in the module manifest cannot be set to *
THIS IS BAD:
# 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 = '*'
THIS IS GOOD:
# Functions to export from this module...
FunctionsToExport = 'Test-Function, Test-Function2'