How to load dll from PS module path - powershell

I have a PS module - all working fine. For a new script which is part of this module I need to load a dll from the Microsoft WindowsAPICodePack
I've added the dll to an "Assemblies" folder within the module, which is installed in the default location (C:\Program Files\WindowsPowershell\Modules\ModuleName).
The script which uses the dll works fine in test, when the dll is in a temp folder e.g. 'c:\temp', however when I run the script from the module, using the path to the dll copy in the module (C:\Program Files\WindowsPowershell\Modules\ModuleName\Assemblies\mydllname.dll) it fails to load the dll with "file not found".
I'm local administrator for the machine so I have access to the path and it also fails if I elevate Powershell before running it.
I need to load the dll from this location without amending permissions for the folder as the module is for distribution to many users via our in-house repository. Any ideas how this can be achieved?
Is there a way to load the dll into the user environment as the module loads instead? This might not work either though as it seems to be a permissions issue on executing/loading dll from the modules path.
I suppose I could run a Set-Acl command against the dll in the .psm1 but this seems a bit clunky and no idea if the install-module process would have required rights?
Example code:
Try {
Add-Type -AssemblyName System.Windows.Forms
Add-Type -Path $DllPath
}
Catch {
$_
Pause
Break
}
If
$DllPath = "C:\Program Files\WindowsPowerShell\Modules\module\dllname.dll"
Then it will fail
If
$DllPath = "C:\temp\dllname.dll"
Then it will succeed
Tried
Added the dll to the module's Required Assemblies in the manifest
Added this to start of the script
Using moduleName
Using namespace Microsoft.WindowsAPICodePack
Same error

Related

Can I run powershell commands without installing module?

I would like to run a script that requires to use commands from the GroupPolicy module. However, this module is not guaranteed to be installed on every machine and some machines might be stand alone. Can I have have the module copied over with my scripts and run commands from it, without installing the module?
Can I have have the module copied over with my scripts and run commands from it, without installing the module?
Yes. Installing a module in PowerShell simply means placing it one of the directories listed in the $env:PSModulePath environment variable, which allows PowerShell to discover it and import (load) it on demand, as part of the module auto-loading feature
However, you're free to copy modules elsewhere, as long as the code that relies on them knows their path and loads them with an explicit Import-Module call.
For instance, if you bundle your script with a GroupPolicy subdirectory containing that module, the script could import it as follows:
# $PSScriptRoot contains the calling script's directory.
Import-Module $PSScriptRoot\GroupPolicy

PowerShell Module cannot be loaded when running Pester test in Visual Studio

I have created a PowerShell test script, Common.tests.ps1, using Pester against some functions in a PowerShell script, Common.ps1, in the same directory.
There is a TestInitializer.ps1 script, also in the same directory, which uses the Microsoft.Xrm.Data.PowerShell module to create and get records in a Dynamics CRM instance.
When running the PowerShell test script from Visual Studio, the test fails in the Test Explorer with a message:
CommandNotFoundException: The module 'Microsoft.Xrm.Data.PowerShell' could not be loaded. For more information, run 'Import-Module Microsoft.Xrm.Data.PowerShell'.
The same test when run from the PowerShell ISE, however, runs without issue. This would seem to be as if the module is not installed for the instance as run by Visual Studio (I confirmed this when running Get-Module -ListAvailable and seeing that the output did not include the Microsoft.Xrm.Data.PowerShell module for the Visual Studio test), though even explicit calls like Import-Module Microsoft.Xrm.Data.PowerShell -Global -Force don't seem to load the module during the script execution with Visual Studio.
Here's Common.test.ps1:
$here = (Split-Path -Parent $MyInvocation.MyCommand.Path)
. $here\Common.ps1
. $here\TestInitializer.ps1
Describe "SelectionToSingleCharString" {
Context "StringTransforms" {
It "Retrieves a CRM record and uses the optionset value to retrieve a single character" {
SelectionToSingleCharString($crmRecord.new_type) | Should Be "I"
}
}
}
Snippet from TestInitializer.ps1:
# Whether or not this is uncommented does not matter
#Import-Module "$env:SystemRoot\System32\WindowsPowerShell\v1.0\Modules\Microsoft.Xrm.Data.PowerShell\Microsoft.Xrm.Data.PowerShell.psd1" -Global -Force
#$modules = Get-Module -ListAvailable
#Write-Host $modules
# Failing here
Microsoft.Xrm.Data.PowerShell\Connect-CrmOnPremDiscovery -ServerUrl $loginServerUrl -OrganizationName $loginOrgName -Credential $cred
I may instead design the test to use Mock instead of actually attempting to create/read records, though not being able to load external modules and run in Visual Studio would be limiting.
Regarding module install directories (skip this if you are interested in the actual problem):
First you should never install modules to $PSHome\Modules (%Windir%\System32\WindowsPowerShell\v1.0\Modules). This folder is reserved for modules shipped with Windows only.
You should always install your modules used only by your user under the following path:
$Home\Documents\WindowsPowerShell\Modules
And for a system-wide installation under:
$Env:ProgramFiles\WindowsPowerShell\Modules
Further reading regarding installing modules in PowerShell can be found on MSDN.
Regarding your actual problem:
What Visual Studio Version are you using? I have Visual Studio 2017 Community edition installed and can not reproduce your error. My PowerShell is also running as a 64-bit process. Your PowerShell could be running as a 32-bit process. For the 32-bit PowerShell the module directories are different. This would explain why the module you installed isn't showing up in Visual Studio.
You can verify if your PowerShell is running in a 64-bit process with the following command:
PS> [Environment]::Is64BitProcess
True
To make your modules accessible for the 32-bit PowerShell you need to install them under the following path as well:
{$Env:ProgramFiles(x86)}\WindowsPowerShell\Modules

Distributing powershell scripts with dll

I have a powershell script that references dll files and i would like to distribute this script to customers. How can i do this such that the customers don't have to worry installing/referencing correct dll files?
I reference the dll files from within the script in the following way:
Add-Type -Path <local path to dll>
I am looking for a way to either bundle these dll's along with the script , or some way for powershell to install the dll when it runs. The dll's i am interested in are available as following nuget packages:
Sharepoint Client
Active Directory library
You could try copying the dll files to the directory the script is in and then use "$PSScriptRoot\Name.Of.File.dll". Zip the directory and distribute the Zip file.

Get-Module -ListAvailable doesn't display my module

I've created a module manifest .psd1 file and I've used Test-ModuleManifest on it which returns nicely and shows the two CmdLets in the binary C# .dll.
The manifest file is in a folder under c:\Program Files\WindowsPowerShell\Modules but when I run Get-Module -ListAvailable it is not showing.
If I run Get-Module it is not showing.
If I run one of the CmdLets then the module is automatically imported and shows when I next run Get-Module.
What am I misunderstanding?? Why doesn't it show as available?
Update
Just done this again with a script module, psm1 and psd1 on a different machine, and same problem. It doesn't show as available and yet posh-git which seems to be setup in a similar way, does.
Okay, the script module does now show up after I fixed a version inconsistency between the version in the manifest and the subfolder name I'd placed it in.
Came in handy:
Test-ModuleManifest

TFS post build powershell script not seeing commands from imported module

We have a TFS build process using a custom template. The build works fine with the crm solution files successfully being created. We are then attempting to run a powershell script on the post build. This script imports a module. But the commands in the module are not being exposed. Whenever we attempt to invoke a command, we get an error. Along the lines of
The term 'Get-XrmSolution' is not recognized as the name of a cmdlet,
function, script file, or operable program.
It doesn't matter which command we use in that module, we get the same kind of error.
To troubleshoot, we have logged onto the build server under the identity of the build account and can successfully run the script we are attempting to run.
Putting some more output into the script to troubleshoot...
Get-Module lists Xrm.Framework.CI.PowerShell. - Good.
Get-Command -Module "Xrm.Framework.CI.PowerShell" returns nothing. From the console, a number of commands are listed.
Is there something we need to do with the running of powershell post build scripts to enable the contents of an imported module to be seen?
Watch out for the bitness of PowerShell invoked by MSBuild and likewise, the bitness of MSBuild launched by Visual Studio. Certain modules only run in either 32-bit or 64-bit PowerShell and not both. You want to make sure the correct version of PowerShell is getting launched.
IIRC you have to explicitly import the module with no assumption of being loaded on user profile, nor on the script path.
Suppose Module1.psm1 is in the same folder as your script, use something like
Import-Module (Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Definition) 'Module1.psm1')
I had the same problem.
The module was loaded in the 'C:\Program Files\WindowsPowerShell\Modules' folder (64 bits).
It all seemed fine when I logged on as the user, but it failed during TFS build.
Solution: I had to uninstall the module in PowerShell 64 bit and re-install in PowerShell 32 bit.
The module was then installed in 'C:\Program Files (x86)\WindowsPowerShell\Modules' folder.