How to use C# interfaces and extension methods in Powershell? - c#

I am trying to use some C# interfaces and extension methods in Powershell. I have loaded necessary binaries at the beginning of the script and written following piece of code:
$environmentsPath = Resolve-Path (Join-Path -Path $PSScriptRoot -ChildPath '..\Deploy.V2\environments')
$configFolder = Join-Path -Path $environmentsPath -ChildPath '.\Stage\configFiles'
$builder = New-Object Microsoft.Extensions.Configuration.ConfigurationBuilder
[Microsoft.Extensions.Configuration.IConfigurationBuilder]$interface = ([Microsoft.Extensions.Configuration.IConfigurationBuilder]$builder)
$interface = [Microsoft.Extensions.Configuration.FileConfigurationExtensions]::SetBasePath($interface, $configFolder)
I am getting following error while trying to run above code:
Cannot convert argument "builder", with value: "Microsoft.Extensions.Configuration.ConfigurationBuilder", for "SetBasePath" to type
"Microsoft.Extensions.Configuration.IConfigurationBuilder": "Cannot convert the "Microsoft.Extensions.Configuration.ConfigurationBuilder" value of type
"Microsoft.Extensions.Configuration.ConfigurationBuilder" to type "Microsoft.Extensions.Configuration.IConfigurationBuilder"."
Even though I have tried to convert object to an interface implementation (at line 4 of the above script) I still see in debugger that it has Microsoft.Extensions.Configuration.ConfigurationBuilder type and the error occurs. I have tried several ways to cast the object but without a success.
Could someone explain me please how can I pass C# function argument being interface implementation in Powershell?

Related

PowerShell and LuaInterface.dll

LuaInterface
Here is an example on c#
Im newbie. How is properly to call this dll?
I was trying this:
[System.Reflection.Assembly]::LoadFile("E:\\lua\\LuaInterface.dll")
$Lua = new-object LuaInterface.Lua # Here IntelliSense see class lua after dot
$lua.DoString("local a=5") # Here IntelliSense see all methods after dot
And this:
Add-Type -path "E:\lua\LuaInterface.dll"
[LuaInterface.Lua]::DoString("local a=5")
But unsuccessfully. Pls, show me example of "3+2" from LuaInterface.
Methods from class Lua PS somehow cant see.
On screenshot powershell can see methods from luaDLL class. But there needed always one more parameter luastate.
You're really close, but :: is only for static member access.
I got the following working in a 32-bit console (PowerShell 5.1):
# Load LuaInterface
Add-Type -Path path\to\luainterface.dll
# Create Lua instance
$lua = [LuaInterface.Lua]::new()
# Set global variable values
$lua['a'] = 2
$lua['b'] = 3
# return result of `a+b`
$lua.DoString("return a+b")

Why can't i return all cimsession functions from Powershell.Invoke() method in c#

I'm running New-CimSession command from both Powershell and C#. When I run it on Powershell, CimSession variable has a lot of functions such as TestConnection(), CreateInstance etc.. Picture is below.
But, CimSession variable type of PSObject doesn't have others functions except ToString() and GetType(), when I run New-CimSession command from Powershell.Invoke() method in c#.
I want to access same method from PSObject variable on c#.
Do you have a idea?
Add Reference to Microsoft.Management.Infrastructure Namespace
Add `using Microsoft.Management.Infrastructure;
static void Main(string [] args)
{
var csession = CimSession.Create("");
csession.TestConnection();
}
csession will have access to different Methods you want
Reference here:
"C:\Program Files (x86)\Reference Assemblies\Microsoft\WMI\v1.0\Microsoft.Management.Infrastructure.dll"
C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.Management.Infrastructure

How to access a PSDrive from System.IO.File calls?

I'm writing a c# cmdlet which copies files from one location to another (similar to rsync). It even supports ToSession and FromSession.
I'd like it to work with PSDrives that use the Filesystem provider but it currently throws an error from System.IO.File.GetAttributes("psdrive:\path")
I'd really like to use calls from System.IO on the PSDrive.
How does something like copy-item do this?
I've performed a search for accessing PSDrives from c# and have returned no results.
This is the equivalent of my code
new-psdrive -name mydrive -psprovider filesystem -root \\aserver\ashare -Credential domain\user
$attributes=[system.io.file]::GetAttributes("mydrive:\path\")
returns
Exception calling "GetAttributes" with "1" argument(s): "The given path's format is not supported."
.NET knows nothing about PowerShell drives (and typically also has a different working directory), so conversion to a filesystem-native path is necessary:
In PowerShell code:
Use Convert-Path to convert a PowerShell-drive-based path to a native filesystem path that .NET types understand:
$attributes=[System.IO.File]::GetAttributes((Convert-Path "mydrive:\path\"))
By default (positional argument use) and with -Path, Convert-Path performs wildcard resolution; to suppress the latter, use the -LiteralPath parameter.
Caveat: Convert-Path only works with existing paths. Lifting that restriction is the subject of the feature request in GitHub issue #2993.
In C# code:
In PSCmdlet-derived cmdlets:
Use GetUnresolvedProviderPathFromPSPath() to translate a PS-drive-based path into a native-drive-based path[1] unresolved, which means that, aside from translating the drive part:
the existence of the path is not verified (but the drive name must exist)
and no wildcard resolution is performed.
Use GetResolvedProviderPathFromPSPath() to resolve a PS-drive-based path to a native-drive-based one, which means that, aside from translating the drive part:
wildcard resolution is performed, yielding potentially multiple paths or even none.
literal path components must exist.
Use the CurrentProviderLocation() method with provider ID "FileSystem" to get the current filesystem location's path as a System.Management.Automation.PathInfo instance; that instance's .Path property and .ToString() method return the PS form of the path; use the .ProviderPath property to get the native representation.
Here's a simple ad-hoc compiled cmdlet that exercises both methods:
# Compiles a Get-NativePath cmdlet and adds it to the session.
Add-Type #'
using System;
using System.Management.Automation;
[Cmdlet("Get", "NativePath")]
public class GetNativePathCommand : PSCmdlet {
[Parameter(Mandatory=true,Position=0)]
public string PSPath { get; set; }
protected override void ProcessRecord() {
WriteObject("Current directory:");
WriteObject(" PS form: " + CurrentProviderLocation("FileSystem"));
WriteObject(" Native form: " + CurrentProviderLocation("FileSystem").ProviderPath);
//
WriteObject("Path argument in native form:");
WriteObject(" Unresolved:");
WriteObject(" " + GetUnresolvedProviderPathFromPSPath(PSPath));
//
WriteObject(" Resolved:");
ProviderInfo pi;
foreach (var p in GetResolvedProviderPathFromPSPath(PSPath, out pi))
{
WriteObject(" " + p);
}
}
}
'# -PassThru | % Assembly | Import-Module
You can test it as follows:
# Create a foo: drive whose root is the current directory.
$null = New-PSDrive foo filesystem .
# Change to foo:
Push-Location foo:\
# Pass a wildcard path based on the new drive to the cmdlet
# and have it translated to a native path, both unresolved and resolved;
# also print the current directory, both in PS form and in native form.
Get-NativePath foo:\*.txt
If your current directory is C:\Temp and it happens to contain text files a.txt and b.txt, you'll see the following output:
Current directory:
PS form: foo:\
Native form: C:\Temp\
Path argument in native form:
Unresolved:
C:\Temp\*.txt
Resolved:
C:\Temp\a.txt
C:\Temp\b.txt
[1] If a PS drive (created with New-PSDrive) referenced in the input path is defined in terms of a UNC path, the resulting native path will be a UNC path too.

Unable to call a method inside a property inside a class from a .NET DLL in Powershell

I have added a dll to my script and declared a new instance of a class from said dll. I've been able to use all properties and methods from that class directly without errors as shown below:
$here = $PSScriptRoot
Add-Type -Path (Join-Path $here 'AudioPrecision.API.dll')
#Declare a variable type APx500
$APX = New-Object AudioPrecision.API.APx500 -ArgumentList True
#Make the window visible
$APX.Visible = "True"
#open a specific project
$APX.OpenProject($here+"\test1.approjx")
Now, It is vital to me to use a method ( Run() ) which is inside a property (Sequence) which inside my already declared class instance. I was able to access a property from said property as shown below:
($APX.Sequence.Count).Count
But when trying to access methods from that Property, it is not working. I am trying the following:
$APX.Sequence.Run()
and I keep getting the following error:
Method invocation failed because [System.MarshalByRefObject] does not contain a method named 'Run'.At C:\Users\eblacio\Documents\Hardware Validation\Audio tests automation\Powershell\Audio Precision API\AP
automation.ps1:18 char:1
+ $APX.Sequence.Run()
I've tried quite a few variants without success.
Any help will be appreciated. Thanks.

Add-Type PowerShell 2.0 can't find method

I've made a c# class that I'm trying to run in PowerShell with add-Type.
I have a few of my own assemblies referenced and some from .net4. I'm using my own PowerShell host because the assemblies I'm referencing are made on the .net4 framework and the PowerShell Console doesn't support that yet.
Here is a sample of the script that i'm trying to run:
$Source = #"
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using MyOwn.Components.Utilities;
using MyOwn.Components;
using MyOwn.Entities;
public class ComponentSubtypeMustMatchTemplate
{
public static Guid ProblemId
{
get { return new Guid("{527DF518-6E91-44e1-B1E4-98E0599CB6B2}"); }
}
public static ProblemCollection Validate()
{
SoftwareStructureEntityContainer softwareEntityStructure = new SoftwareStructureEntityContainer();
if (softwareEntityStructure == null)
{
throw new ArgumentNullException("softwareStructure");
}
ProblemCollection problems = new ProblemCollection();
foreach (var productDependency in softwareEntityStructure.ProductDependencies)
{......
return problems;
}
}
"#
$refs = #("d:\Projects\MyOwn\bin\MyOwn.Components.dll",
"d:\Projects\MyOwn\bin\MyOwn.Entities.dll",
"d:\Projects\MyOwn\bin\MyOwn.OperationalManagement.dll",
"c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll",
"c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Data.Entity.dll",
"c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Data.dll")
Add-Type -ReferencedAssemblies $refs -TypeDefinition $Source
$MyProblemCollection = new-Object ComponentSubtypeMustMatchTemplate
$MyProblemCollection.Validate()
Now when i run this I get this error:
{"Method invocation failed because [ComponentSubtypeMustMatchTemplate] doesn't contain a method named 'Validate'."}
Ive also tried the last bit in different ways (found many different examples on how to do this) but they all seem to give the same error. I really have no idea how to get this working, and i can't seem to find any example's on something similar.
On a second note(for when i get this fixed) I was wondering if it was possible to be able to just load the .cs file instead of putting the c# code in the script. would be a better read and more maintainable.
Ive tried to see if I can see the methods with Get-Member -static like this:
$MyProblemCollection = New-Object ComponentSubtypeMustMatchTemplate
$MyProblemCollection | Get-Member -Static
And it does see the method there:
TypeName: ComponentSubtypeMustMatchTemplate
Name MemberType Definition
---- ---------- ----------
Equals Method static bool Equals(System.Object objA, System.Obje...
ReferenceEquals Method static bool ReferenceEquals(System.Object objA, Sy...
Validate Method static MyOwn.ComponentSubtypeMustMatchTemplate... <--
ProblemId Property static System.Guid ProblemId {get;}
So why doesn't it work!?
#Philip
in my script it doesn't really matter if its static or non static cause it will always just be run once and the results will be used my program. But strange thing is it does seem to work if i use the static syntax (except for that i get no results at all) and if i use the non-static syntax i'll get the same error. I also tried the script in an other PowerShell console i found on the interwebs, and there i get an entirely different error :
PS C:\temp.
ps1
The following exception occurred while retrieving member "Validate": "Could not
load file or assembly 'MyOwn.Entit
ies, Version=1.0.0.0, Culture=neutral, PublicKeyToken=fc80acb30cba5fab' or one
of its dependencies. The system cannot find the file specified."
At D:\Projects\temp.ps1:145 char:30
+ $MyProblemCollection.Validate <<<< ()
+ CategoryInfo : NotSpecified: (:) [], ExtendedTypeSystemExceptio
n
+ FullyQualifiedErrorId : CatchFromBaseGetMember
hmm nvm, it spontaneously worked! strange BUT i'm happy! =)
Your method is static, but you are trying to call it via an instance.
$MyProblemCollection = new-Object ComponentSubtypeMustMatchTemplate
Creates a new instance of ComponentSubtypeMustMatchTemplate.
$MyProblemCollection.Validate()
Calls the instance method named Validate on the object referenced by $MyProblemCollection. However, since there is no instance method named Validate, the call fails.
You can either make the methods non-static (which you would do if they were going to keep state in the object), or you can use a different powershell syntax used to call a static method:
$result = [ComponentSubtypeMustMatchTemplate]::Validate()
Remember ( if you keep these static ) that setting a static property means anything querying that property in the same process will get that value. If you are holding state, then I would advise removing the static from each declaration.

Categories