Powershell import external DLL [duplicate] - powershell

I created a dll in C# and would like to use it in PowerShell.
I know I can load the dll using:
[Reflection.Assembly]::LoadFile("MyDll.dll")
But I don't want to use reflection.
Is there a simple way to do include my dll without reflection? Something like add reference to this dll?

In PowerShell 2.0 the cmdlet Add-Type is designed for this, for example:
Add-Type -Path "$env:Xyz\bin\Npgsql.dll"
(it’s more likely that under the covers it calls the same LoadFile but this way is more PowerShell-ish)

Related

Loading/use CsvHelper in PowerShell 7/.NET 5

Long story short - requesting assistance loading/using CsvHelper in PS 7 w/.NET 5. Dll loads fine but no exported commands available. Added a manifest (nested, root, etc) with full export didn't expose. Assistance would be greatly appreciated.
Long story long - Have a system with fairly vanilla installs of pwsh v7.1.3 and .NET v5.0.300. I've been assigned a project to work with very large CSV files and process them with SQLBULKCOPY. The files will have formatting challenges as well as date (datetime2) fun so a Csv parser seems to be the best course of action.
After seeing that CsvHelper can cut through the parsing requirements, is compiled for .NET 5 (no dependencies), and reading reviews showing 20%+ better performance than another DLL (lu...) being tested I would like to leverage it for the project.
This solution will be used on systems with no access to the internet and users with limited skills, so the hope is to use just include the CsvHelper dll in the script module directory.
Loading the CsvHelper.dll (net5.0) file import-module "...\CsvHelper.dll" appears to work. Get-Module shows the dll is loaded but doesn't show any exported commands. Get-Command doesn't either. I've tried creating a manifest file for the DLL (nestedmodules, rootmodule, etc. and export specific publics, *) but am unsuccessful. I'm sure I'm missing something simple and would appreciate assistance. Thanks much.
When I started this project the first test was using a Lumenworks parser. It can be loaded into PS and used directly. That was nice and it set my head in that specific direction. Moving into CsvHelper I was wanting (hoping) to stay in PS only. There were bureaucratic motivations to not to go into studio, compile a dll, and the like.
My hope was to load the helper dll in PS and then inline the C# code. Something along the lines of:
Import-Module "C:\...\CsvHelper.dll"
or
$Assem = (
<?? for csvhelper>
)
with
$source = #"
using CsvHelper;
<C# around using CsvHelper>
"#
and appropriate Add-Type
Add-Type -ReferencedAssemblies $Assem -TypeDefinition $Source -Language CSharp
What I wanted to do can probably be done but I don't have the skills for it. For now I'm going with a Studio project. Will build set it to do what I want, use it in PS for the solution and deal with the politics.
Appreciate the inputs.

access .NET framework tools from powershell

How to access several .NET framework tools from powershell? The tools are listed in the following link :
https://learn.microsoft.com/en-us/dotnet/framework/tools/.
I got to found out that the tools are located under the following path :
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools
How to initiate the script so that we can do the following:
Identify if .NET framework tools are installed or not.
2.Install it if not installed and extract the installed path .
Go to the path and use of the tools for further use.
Today the powershell script is formulated in a way that requires users interaction to point to one of the .NET framework tools, for example CorFlags.exe. The idea is to remove this interaction and locate the file by powershell script if .NET framework tools are already installed or install it first and then locate it.
$CorFlagsExe = (Find-FileDialog -Title "Select CorFlags.exe." -InitialDirectory "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools" -ExtensionFilter "CorFlags.exe")
foreach($f in $Files)
{
& $CorFlagsExe $f.FullName /32BITREQ- /nologo
}
The basic approach is pretty straight-forward
Load desired dll. Using an itext dll for this example. In your case, you need to determine which netfx dll has the netfx class you need to do what it is you want to do
[Reflection.Assembly]::LoadFile(:C:\foo\itext.kernel.dll") | out-null
Example: Instantiate an itext PdfWriter object. The ctor requires a fully qualified pdf file name. In your case, once you know which netfx class you need, you need to find the class docs and determine which ctor you need for the object you want to instantiate
[itext.kernel.pdf.PdfWriter]$pdfWriter = New-Object itext.kernel.pdf.PdfWriter("fully qualified pdf file name")
Example of involving an object method. In your case, study the class docs to learn which methods and and properties you need to use to do what it is you want to do
$pdfWriter.close()
This is a trivial example but it should get you going.
This is what the Add-Type cmldet is for.
Add-Type was added in PowerShell 2.0, so prior to that, the Assembly::Load method was the only way to add assemblies to your namespace. Since PowerShell 3x and beyond, it's improved.
Add a .NET Framework type to a PowerShell session. If a .NET Framework
class is added to your PowerShell session with Add-Type, those objects
may then be instantiated (with New-Object ), just like any .NET
Framework object.
Add-Type -AssemblyName accessib* -PassThru
As for whether you use Add-Type of what 'Nova Sys Eng' has highlighted, there is a good article below on that topic.
Add-Type vs. [reflection.assembly] in PowerShell
There's also an undocumented "using assembly" command (although in ps 6 and above you have to special the path to the dll because there's no more GAC).
using assembly System.Windows.Forms
using namespace System.Windows.Forms
[messagebox]::show('hello world')

Problems when loading Assemblies in PowerShell

I'm currently building a powershell transfer script that uses WinSCP assembly to upload files. I have defined a class in which I'm initializing things like the WinSCP.SessionOptions etc. These types are defined in the WinSCPnet.dll. At the beginning of my script I'm importing the assembly with
Add-Type -Path <Path-to-assembly.dll>
Later in my class definition I have a variable like this that is not yet initialized
[WinSCP.SessionOptions]$Script:SessionOptions
When I try to run the script I always get "Type not found" error referencing to the line where I'm declaring the uninitialized variable.
This problem is not limited to the WinSCP assemblies. I'm also getting it when I call a static method no matter if it's a system or a custom assembly.
What can I do to solve that?
Thanks in advance.

New-CryptographyKey module Powershell

I have been working on a script and I needed to use Encryption/Decryption. Basically, encrypt a text file and then add the decryption code in my script and then let the script do its work by taking the encrypted file and decrypting it. After googling through stuff, I came across this post. By far it seemed the most simple implementation for my work. However, I am unable to import this module in my PS window.
When I write:
Import-Module New-CryptographyKey
I get the error:
Import-Module Cannot find path 'C:\WINDOWS\system32\New-CryptographyKey' because it does not exist.
I understand that this is some path issue but I have set the path in the environment.
Any suggestions will be helpful.
Your problem is how you're importing the module. Because the technet link you have in your question is directly to a .psm1 file, you need to fully-path that in your import command (as it does not have a proper module manifest):
Import-Module -Name 'C:\path\to\FileCryptography.psm1'
With this, it should work.
The alternative is you generate a module manifest, learn how module loading works and have the folder/files in the right location/named correctly, and then it can be auto-loaded on v3+, but that's a little outside the scope of this question.
So what I was missing was to importing the module as stated by TheIncorrigible1. After that, I was also missed adding the Assembly as follows in the Script.:
Add-Type -Assembly System.Security
Add-Type -AssemblyName System.Windows.Forms
How this worked is that I used the Technet link and understood what he was doing and used the assemblies that he imported in my script and extracted the Encrypting and the Decrypting statements he used. This seemed to work for me.
This happened because I was unable to Import the New-CryptographyKey because I was not specifying the path. So for anyone else, better to import the module with its path when you are facing this issue.
Thanks Incorrigible1 for letting me know of this, however I made this work in a noob way but the correct way to import it was by giving the correct path as
Import-Module -Name 'C:\path\to\FileCryptography.psm1'

PowerShell App.Config

Has anyone worked out how to get PowerShell to use app.config files? I have a couple of .NET DLL's I'd like to use in one of my scripts but they expect their own config sections to be present in app.config/web.config.
Cross-referencing with this thread, which helped me with the same question:
Subsonic Access To App.Config Connection Strings From Referenced DLL in Powershell Script
I added the following to my script, before invoking the DLL that needs config settings, where $configpath is the location of the file I want to load:
[appdomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $configpath)
Add-Type -AssemblyName System.Configuration
See this post to ensure the configuration file specified is applied to the running context.
I'm guessing that the settings would have to be in powershell.exe.config in the powershell directory, but that seems to be a bad way of doing things.
You can use ConfigurationManager.OpenMappedExeConfiguration to open a configuration file based on the executing DLL name, rather than the application exe, but this would obviously require changes to the DLLs.
Attempting a new answer to an old question.
I think the modern answer would be: don't do that. PowerShell is a shell. The normal way of passing information between parts of the shell are shell variables. For powershell that would look like:
$global:MyComponent_MySetting = '12'
# i.e.
$PSDefaultParameterValues
$ErrorActionPreference
If settings is expected to be inherited across processes boundaries the convention is to use environment variables. I extend this to settings that cross C# / PowerShell boundary. A couple of examples:
$env:PATH
$env:PSModulePath
If you think this is an anti-pattern for .NET you might want to reconsider. This is the norm for PAAS hosted apps, and is going to be the new default for ASP.NET running on server-optimized CLR (ASP.NET v5).
See https://github.com/JabbR/JabbRv2/blob/dev/src/JabbR/Startup.cs#L21
Note: at time of writing I'm linking to .AddEnvironmentVariables()
I've revisited this question a few times, including asking it myself. I wanted to put a stake in the ground to say PowerShell stuff doesn't work well with <appSettings>. IMO it is much better to embrace the shell aspect of PS over the .NET aspect in this regards.
If you need complex configuration take a JSON string. POSH v3+ has ConvertFrom-JSON built-in. If everything in your process uses the same complex configuration put it in a .json file and point to that file from an environment variable.
If a single file doesn't suffice there are well established solutions like the PATH pattern, GIT .gitignore resolution, or ASP.NET web.config resolution (which I won't repeat here).