Odd behavior with DefaultCommandPrefix and NestedModules - powershell

I created a module, that imports nested modules and it doesn't work right if I set the default command prefix.
One of the recommendations I found on the web was to make the module easier to maintain by creating new folders and separate files for the modules.
So I have
Module.psm1
Common\Common.psm1
Get-Data
Company\Company.psm1
Get-Company
I am also trying to use the Default Command Prefix option as well. When I add that, and then try and use the module it breaks.
Without Command prefix, I'm able to call get-company, which is able to call get-data and everything is happen.
When I ADD command prefix, I can no longer call Get-Data. If I move the Function Get-Company to the Module file then it is able to call Get-Data.
Am I doing something wrong here, is this an odd bug, is this expected behavior, Details on the Default Command Prefix are very sparse here:How to Write a PowerShell Module Manifest

Related

Is there a way to search across all scripts in a deployment?

I have a PowerShell script module in a deployment, which defines a function that seems to be going wrong. Unfortunately, because it's in a script module, I don't know where the call to it is coming from, and it's a very large and complicated deploy with many steps.
Is there any way to run a text search for the name of this function across all scripts used in the entire deployment?
If you are using inline scripts in your deployment process you can download the entire process to a JSON file, via the overflow menu on the process edit page.
The script body for each step is contained within the property:
Octopus.Action.Script.ScriptBody.
If you are using scripts sourced from packages you will need to check in your source repositories for references to the script module function, the JSON for the step will contain the following properties:
"Octopus.Action.Script.ScriptSource": "Package",
"Octopus.Action.Script.ScriptFileName": "script1.ps1",
"Octopus.Action.Package.PackageId": "packageId",

How to make parameter name suggestions work?

I'm trying to create a powershell module to store some reusable utility functions. I created script module PsUtils.psm1 and script module manifest PsUtils.psd1 (used these docs). My problem is that when I import this module in another script Visual Code does not suggest parameters names. Here's a screenshot:
When I hover cursor over the function I only get this:
PsUtils.psm1
function Get-Filelist {
Param(
[Parameter(Mandatory=$true)]
[string[]]
$DirectoryPath
)
Write-Host "DIR PATH: $DirectoryPath"
}
PsUtils.psd1 (excerpt)
...
FunctionsToExport = '*'
I have Powershell extension installed. Do I need to install anything else to make the suggestions work? What am I missing?
Generally speaking, only auto-loading modules - i.e., those in one of the directories listed in environment variable $env:PSModulePath - are automatically discovered.
As of version v2022.7.2 of the PowerShell extension, the underlying PowerShell editor services make no attempt to infer from the current source-code file what modules in nonstandard directories are being imported via source code in that file, whether via Import-Module or using module
Doing so would be the prerequisite for discovering the commands exported by the modules being imported.
Doing so robustly sounds virtually impossible to do with the static analysis that the editor services are limited to performing, although it could work in simple cases; if I were to guess, such a feature request wouldn't be entertained, but you can always ask.
Workarounds:
Once you have imported a given module from a nonstandard location into the current session - either manually via the PIC (PowerShell Integrated Console) or by running your script (assuming the Import-Module call succeeds), the editor will provide IntelliSense for its exported commands from that point on, so your options are (use one of them):
Run your script in the debugger at least once before you start editing. You can place a breakpoint right after the Import-Module call and abort the run afterwards - the only prerequisite is that the file must be syntactically valid.
Run your Import-Module command manually in the PIC, replacing $PSScriptRoot with your script file's directory path.
Note: It is tempting to place the cursor on the Import-Module line in the script in order to use F8 to run just this statement, but, as of v2022.7.2, this won't work in your case, because $PSScriptRoot is only valid in the context of running an entire script.
GitHub issue #633 suggests adding special support for $PSScriptRoot; while the proposal has been green-lighted, no one has stepped up to implement it since.
(Temporarily) modify the $env:PSModulePath variable to include the path of your script file's directory.
The most convenient way to do that is via the $PROFILE file that is specific to the PowerShell extension, which you can open for editing with psedit $PROFILE from the PIC.
Note: Make sure that profile loading is enabled in the PowerShell extension's settings.
E.g., if your directory path is /path/to/my/module, add the following:
$env:PSModulePath+="$([IO.Path]::PathSeparator)/path/to/my/module"
The caveat is that all scripts / code that is run in the PIC will see this updated $env:PSModulePath value, so at least hypothetically other code could end up mistakenly importing your module instead of one expected to be in the standard locations.
Note that GitHub issue #880 is an (old) proposal to allow specifying $env:PSModulePath entries as part of the PowerShell extension settings instead.
On a somewhat related note:
Even when a module is auto-discovered / has been imported, IntelliSense only covers its exported commands, whereas while you're developing that module you'd also like to see its private commands. Overcoming this limitation is the subject of GitHub issue #104.

ImportPSModulesFromPath doesn't add anything to the Modules collection

I've got a Powershell module which I'm needing to load into a Runspace for use by different threads. I understand that defining a SessionState allows me to load modules in that can then be accessed by the runspace:
$SessionState = [System.Management.Automation.Runspaces.InitialSessionState]::Create()
$SessionState.ImportPSModulesFromPath("$filepath\Validation Library.psd1")
$runspacePool = [runspacefactory]::CreateRunspacePool($SessionState)
The problem is that I can't seem to get ImportPSModulesFromPath to do anything - it doesn't return any errors, yet the $SessionState.Modules collection is always empty, and my Runspace keeps returning errors saying it can't find the functions in the module, even though they're defined properly in the psd1 and do work if I load normally using Import-Module.
The psd1 file contains the module definition pointing to a psm1 file in the same folder (I get the same behaviour when pointing directly to the psm1)
After lots of searching and testing, I was unable to determine anything wrong with the script - until I closed and reopened my Powershell session.
Though I had been taking care to dispose and remove variables I thought were being used, I had been running the same scripts with the same variables repeatedly, and so something incorrect had been stored down into one of my variables, causing the module load to fail.
Running the same script in a new session showed that the module was loading successfully.

Putting "using namespace ..." to PowerShell Module .psm1 script is not working after module is imported

I'm writing a PowerShell module that is using as wrapper for .Net (DotNet) Assembly 'Framework.Core.Measurements.dll'.
The PowerShell version is 5.1.* under Windows 7 64 bits.
In my .psd1 file added the assembly to the RequiredAssemblies list the assembly:
RequiredAssemblies = #('Framework.Core.Measurements.dll')
I
In my .psm1 I added "using namespace" statement:
using namespace Framework.Core.Measurements
I used "Import-Module -Verbose" to verify that .pdm1 is indeed being executed.
After imported successfully I try to use the Angle enum I have in the "Framework.Core.Measurements" namespace, but PowerShell does not recognized it despite the "using namespace ..." statement that was executed in the .psm1 script.
If I type the "using namespace Framework.Core.Measurements" statement in the PowerShell command prompt then it works.
Any idea or work around?
You cannot import namespaces for the importer of your module via a *.psm1 file:
A using namespace statement takes effect for the scope in which it is executed and all descendant scopes, which is why executing such a statement inside a *.psm1 file has no effect on the scope that imports the module.
The workaround is to place the call in a *.ps1 script that you must reference from your module manifest's ScriptsToProcess entry (see the New-ModuleManifest help topic).
Such scripts are run directly in the importing code's scope (they are dot-sourced), but note that this only happens the first time a given module is imported into a session - see this GitHub issue.
Note: While assemblies referenced via the RequiredAssemblies entry are loaded before the scripts specified via ScriptsToProcess are dot-sourced in the caller's scope (see below), the order doesn't really matter:
As you've discovered, PowerShell allows you to execute a using namespace statement irrespective of whether any assemblies with types in that namespace are loaded at that time; instead, PowerShell looks in whatever namespaces you've previously passed to using namespace whenever you attempt to access a type by mere name (e.g., [Angle]).
As an aside: Generally, the elements of a module being imported are executed in the following order:
Loading of the assemblies specified in RequiredAssemblies.
Dot-sourcing of the scripts specified in ScriptsToProcess.
Recursive importing of any nested modules specified in NestedModule.
Importing of the main module specified in RootModule.
I didn't consider using ScriptsToProcess the first place cause accoring to the documentation it's scripts ran prior to the module importing.
That is, I was certain that the .Net assembly should be already loaded before running "using namespace" for any of namespaces it has.
Now I realize that one can run using namespace statement even though there is no code that is currently associated with it.
Your answer helped me alot.
Thank you.

Powershell Module Manifest "ScriptsToProcess"

I have a powershell module I am writing and one thing I was curious of that is a bit unclear is the ScriptsToProcess Key. Can or should I use this to verify certain things like OS Type, Bit Type, or the presence or lack of certain environment variables to throw warnings if some of my functions may rely on some of the requirements above?
You can use ScriptsToProcess to execute script in the caller's session state (create variables, etc) or to use Write-Warning to notify the user the prereqs haven't been met. However, even if you throw an error, the module is still loaded. So if your intent is to prevent loading of the module I would put the warnings/throws in the startup script of your ModuleToProcess/RootModule. The module will show up in the Get-Module list but there shouldn't be any exported commands. Also if you want to check bitness, use the module manifest ProcessorArchitecture key.