I am having trouble understanding why I cannot achieve the following:
Create a set of variables in a module.
Have a function in the module do something and update the parent scope variable with the changed value.
Import the Module into a script that calls the same function and have the updated value available to the script that imported the module.
For example
Module Lib has the following:
$psVarx = -1
function Init {
$psVarx = 2
$script:psVarx = $psVarx
}
Export-Member -variable $psVarx
And the script using the module has the following:
Import-Module Lib -Force
Init
"psVarx is {0}" -f $psVarx
The output received is
psVarx is -1
The question is if I updated the script scoped copy of the variable in the module, why does the script using the module not see the updated value of the variable? I am pretty sure the issue has to do with scoping. What am I missing here?
What is the recommended method for initializing module variables in the situation where the module has work it needs to do to initialize itself and set variables that then should be made available to the code that is Importing the module?
In this particular case I have dozens of variables that I would like to initialize within a module and then export the newly initialized values.
In PowerShell V3 the following works:
$psVarx = -1
function Init {
$psVarx = 2
$script:psVarx = $psVarx
}
Export-ModuleMember -variable psVarx -Function init
Notice that psVarx (not $psVarx) is passed to Export-modulemember (not Export-Member). Also Init is specified.
Related
I had a powershell script, which I am not trying to convert to an Azure Function. The script is quite simple, but uses function definitions - something like this:
function InternalFunction {
# Do some processing
...
}
$someData = ...
$someOtherData =
...
# now call internal function
InternalFunction $someData
...
InternalFunction $someOtherData
Now I put this code in run.ps1 in my Azure function code - and it fails complaining that InternalFunction is not a known cmdlet. Specifically, I get this in the log:
The Function app may be missing a module containing the 'InternalFunction'...
So, is there a way to do it using "internal" functions or do I need to rewrite everything to be one function?
You're probably better off defining your functions inside a module and uploading the module with your code.
You can add your own modules by creating a Modules folder at the root of your functionapps directory, this is then appended to your $PSModulePath when the host starts up so that your module is discoverable.
You can find the docs on the folder structure here
I have defined this in module as defblah.ps1
$defblah= #{
first = "aaa";
seconf = "bbb";
}
I also have this in module as Blah.ps1
Function Blah
{
Write-Host $defblah.first;
}
I did Export-ModuleMember and then Import-Module, so everything with module definition (export, import) is fine.
Then, after importing I run Blah, it prints "aaa", which is what i expected.
The problem is when I type in
Write-Host $defblah.first;
it returns nothing. How can I make my last statement work and return "aaa"?
Generally, I suggest not exporting variables from a module, even though it is technically supported.
A module's implicit export behavior indeed precludes variables - in PSv5+, only functions and aliases are exported by default - meaning the absence of an Export-ModuleMember and/or module manifest (*.psd1) controlling the exports.
The general expectation is for a module to export commands (functions / cmdlets and possibly also aliases), not data (variables) - and commands alone present enough potential for name collisions.
If you truly want to export variables from your module, use an Export-ModuleMember call with the
-Variable parameter and/or - if your module comes with a manifest file - export the variables via the VariablesToExport key.
I have a simple powershell module containing a single function, an abridged version of this is as follows:
function My-Func
{
.
.
.
}
Export-ModuleMember -Function 'My-Func'
My manifest file contain a line to explicitly export this:
FunctionsToExport = "My-Func"
Everything uploads to the powershell gallery via Publish-Module without any problems, then when I come to install this and run Get-Module, I do not see the function in the export commands column of the output, also I when I attempt to call the function powershell tells me it does not exist.
I have a psm1 file for my module and a psd1 manifest, for some reason when I only see Manifest as the module type, I'm guessing I need to see script ?.
Any ideas ?
in your .psm1:
remove the Exported-ModuleMember line
in your .psd1:
RootModule = 'yourmodule.psm1'
FunctionsToExport = #('function1','function2')
the psd1 file FunctionsToExport works like the Exported-ModuleMember command. it's a cleaner way to define things from one centralized file.
I created a class in a ps1 file that works just fine IN the ps1 file itself. I can run various tests with the class and the tests in the same file.
My trouble is I don't seem to be able to find a way to put my Class in one file and the Class Usage code in another.
With functions, you can just dot source them to bring any external ps1 files into your current script. It looks like Classes for Powershell do not work this way.
How can I organize code to keep classes in separate files from the executing script?
Do I have to use modules? How do I do that?
In the file Hello.psm1:
class Hello {
# properties
[string]$person
# Default constructor
Hello(){}
# Constructor
Hello(
[string]$m
){
$this.person=$m
}
# method
[string]Greetings(){
return "Hello {0}" -f $this.person
}
}
In the file main.ps1:
using module .\Hello.psm1
$h = New-Object -TypeName Hello
echo $h.Greetings()
#$hh = [Hello]::new("John")
$hh = New-Object -TypeName Hello -ArgumentList #("Mickey")
echo $hh.Greetings()
And running .\main.ps1:
Hello
Hello Mickey
This may not apply to your case, but I have had nightmares with PowerShell caching information (in my case it was just for modules). Things I'd changed in the module weren't being properly loaded - even after a reboot.
I found deleting the cache stored in a subdirectory of C:\Users\<YourUsername>\AppData\Local\Microsoft\Windows\PowerShell solved my issue.
The simplest solution is to use the using keyword, at the very beginning of your script :
using module .\path\to\your\Module.psm1
Path can be relative from your current file.
To prevent caching problem, use powershell.exe .\script.ps1 to execute it, even in the PoweShell ISE console.
I have a powershell module file C:\Program Files\WindowsPowerShell\Modules\MathModule\MathModule.psm1
I have added this so that I can access the functions in the module easily from anywhere. Lets say this contains a function called Add-Numbers.
I have another project where I have MathModule.psm1 with another implementation of Add-Numbers function. From test.ps1 in the same directory I write
Import-Module ".\MathModule.psm1"
Add-Numbers 1 2 3
I was expecting this to use the Add-Numbers definition from the locally imported MathModule.psm1. However, it continues to use the definition from C:\Program Files\WindowsPowerShell\Modules\MathModule\MathModule.psm1
How can I override Add-Numbers from local MathModule.psm1 in test.ps1 instead of the one in Program Files?
If the MathModule module was previously loaded you'll need to add -Force to truly reload it (even from a different psm1 file).