access .NET framework tools from powershell - 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')

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.

Load System.IO.Compression.FileSystem with Add-Type throws error

I want to extract a zip file using PowerShell. So, I use this:
Add-Type -AssemblyName System.IO.Compression.FileSystem
# some code to download the zip file from FTP #
[System.IO.Compression.ZipFile]::ExtractToDirectory($localpath+"\Test.zip",$localpath)
I get error: Add-Type : Cannot add type. The assembly 'System.IO.Compression.FileSystem' could not be found.
I then searched StackOverflow and changed
Add-Type -AssemblyName System.IO.Compression.FileSystem
to
Add-Type -Path "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.IO.Compression.FileSystem.dll"
It says:
Error: Could not load file or assembly 'file:///C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFram
ework\v4.6.1\System.IO.Compression.FileSystem.dll' or one of its dependencies. This assembly is built by a runtime newer
than the currently loaded runtime and cannot be loaded.
I can actually see this dll in that v4.6.1 path. It is there. What is wrong with my syntax, please?
There is nothing wrong with your syntax; the problem is that the assembly is not compatible with your version of PowerShell - which is exactly what the second error says. For the first error, PowerShell might simply not have that path as part of the path that it searches for assembly DLLs because they're not compatible (again, see the error for the second attempt, where you specified the correct path for the assembly).
If you can, you might want to consider updating your PowerShell (and Windows Management Framework). The current version of PowerShell is 5.
If you are using Powershell version 5+ you can use Expand-Archive to unzip files. See this msdn link.
I had a similar problem using Compress-Archive which worked on Win10 but not on Win Srv 2012 R2 even thought the syntax was correct and the DLL existed per paths above.
I noticed then that the version of PowerShell on Win10 was 5 and on WinSrv was 4 so I installed Windows Management Framework (WMF) 5.1 which includes and update to PS and then when the ver of PS on WinSrvR2 was also 5, this command then worked.

Powershell import external DLL [duplicate]

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)

Determine difference between COM and .NET DLLs in Powershell

I'm writing a script to copy and move DLLs from the bin folder to a mapped drive, and I need to register/unregister the DLLs during the process. I've figured out how to do all of this, but there's a catch. The program I'm working on utilizes VB6 COM DLLs and VB.NET .NET DLLs. I understand that COM DLLs use regsvr32.exe, and .NET DLLs use regasm.exe, but I am interested in programmatically calling the correct function, based upon the DLL I am moving. Is there a way to determine what time I am using in Powershell?
Call
[Reflection.Assembly]::LoadFile( `mydll.dll`)
It should raise a BadImageFormatException if it is not a .Net dll.
As per MSDN:
"This exception is thrown when the file format of a dynamic link library (.dll file) or an executable (.exe file) does not conform to the format that is expected by the common language runtime. In particular, the exception is thrown under the following conditions:
...
An attempt is made to load an unmanaged dynamic link library or executable (such as a Windows system DLL) as if it were a .NET Framework assembly. The following example illustrates this by using the Assembly.LoadFile method to load Kernel32.dll."

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