powershell: run code when importing module - powershell

I have developed a powershell module in C#, implemented a few commands.
How can I execute C# code in this module when it's imported by Powershell?

Create a module manifest with the ModuleToProcess (or RootModule in V3) field set to the PSM1 file and the NestedModules set to the DLL e.g.:
RootModule = 'Pscx.psm1'
NestedModules = 'Pscx.dll'
This is what we do in the PowerShell Community Extensions where we do the same thing - fire up a script first. You can see our PSD1 file here.

This is a very basic solution, simply replace code within the {} with your source. (my test below)
add-type 'public class c{public const string s="Hello World";}';[c]::s
enjoy

I'm also writing a binary cmdLet in .NET. I have found that if you create a class that inherits from at least DriveCmdletProvider, that class can implement InitializeDefaultDrives.
This method will get call when import-module is called on your DLL.
You could use this 'feature' to stand up some session (or module session) data.

Related

PowerShell Azure function - use internal function

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

Powershell module function not visible in Get-Modules

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.

How to Access Custom PowerShell 5.0 Classes from a separate ps1 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.

How to override powershell global module functions?

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).

How do I turn a collection of script files into a module?

Do you guys know, whether it's possible to convert PowerShell project consisting solely of functions, into module? What I want to achieve is to create distributable module of all my functions so others can use it. But without spending time of converting all functions into cmdlets.
Each of my functions is in separate file. When I then create *.psd1 and I try to include functions via 'FunctionsToExport', it doesn't work. I can't see my functions after module is loaded.
Is it even possible to export function from module when they're NOT (all of them) inside a .psm1 file? I'm still trying to figure out real differences and use of *psd1 and *psm1 files.
Yes, you can turn a bunch of .ps1 files into a module. Create a new folder in your module directory $env:USERPROFILE\Documents\WindowsPowerShell\Modules and put all the .ps1 files in that folder. Also create two text files <foldername>.psm1 and <foldername>.psd1 in the folder, so that you have a structure like this:
$env:USERPROFILE
`-Documents
`-WindowsPowerShell
`-Modules
`-MyModule
+-MyModule.psd1
+-MyModule.psm1
+-script1.ps1
+-script2.ps1
:
`-scriptN.ps1
Put the following line in the .psm1 file, so that it "imports" all .ps1 files:
Get-ChildItem -Path "$PSScriptRoot\*.ps1" | % { . $_.FullName }
and specify your metadata in the module manifest (the .psd1 file), e.g.:
#{
ModuleToProcess = 'MyModule.psm1'
ModuleVersion = '1.0'
GUID = '6bc2ac1e-2e88-4bc3-ac84-ecd16739b6aa'
Author = 'Matthew Lowe'
CompanyName = '...'
Copyright = '...'
Description = 'Description of your module.'
PowerShellVersion = '2.0'
FunctionsToExport = '*'
CmdletsToExport = ''
VariablesToExport = ''
AliasesToExport = ''
}
A GUID can be generated for instance via [guid]::NewGuid().
Here's a very simple way of doing it, without including your functions through dot sourcing mode, as it's done in the other answer:
Create a folder C:\MyModules.
Inside this folder, create an empty file named MyModules.PSM1.
Append to MyModules.PSM1 file, all functions (they don't need to be advanced) you want in the module.
YOU ARE DONE.
Now, you have a folder ( C:\MyModules ) that you must install in the target machine.
To install it in the target machine (per user), copy the folder C:\MyModule to the user's default module location (i.e. folder): $home\Documents\WindowsPowerShell\Modules.
Now, this user can type in any PowerShell session the first letter(s) of any function included in your module, that PowerShell's IntelliSense will recognize the function from your module (and uggest the completion substring).
If you don't like the name MyModule, you can change it, as long as you change the folder name as well as the PSM1 file name.
You can also opt to install your module for all users: help about_modules.