Let's say you wrote a totally awesome function in C# and want to use it in your PowerShell script. You can do this like so:
$Source = #"
public class BasicTest
{
public static int AddNumbers(int a, int b)
{
return (a + b);
}
}
"#
Add-Type -TypeDefinition $Source
[BasicTest]::AddNumbers(4, 3)
# output: 7
The question is, how to call this function without [BasicTest]:: part? Like this:
AddNumbers(4, 3)
What I tried (and it didn't work)
using namespace BasicTest
Set-Alias -Name AddNumbers -Value [BasicTest]::AddNumber
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
The below C# snippet is embedded in a powershell (.ps1) file and generated an System.Management.Automation.RuntimeException. Removing "string s" and the exception goes away. Tried to use uppercase "String" and tried to add namespace "System.String" and various other approaches but still get the exception. This is driving me nuts, please help me understand why this is happening.
$code = #"
public static class foo
{
public static bool check()
{
string s;
return false;
}
}
Code is invoked like this;
try
{
Add-Type -TypeDefinition $code -Language CSharp
}
catch{} // ignore TYPE_ALREADY_EXISTS exception
$res = [foo]::check();
Here is exception details;
Exception: System.Management.Automation.RuntimeException: unable to find type [foo].
TargetObject: foo
CategoryInfo: InvalidOperation (foo:Typename) [], RuntimeException
FullyQualifiedErrorId: TypeNotFound
InvocationInfo: System.Management.Automation.InvocationInfo
$code = #"
public static class foo {
public static bool check() {
string s;
return false;
}
}
"#
Add-Type -TypeDefinition $code -Language CSharp
produces
Warning as Error: The variable 's' is declared but never used
It will not allow you to declare unused variables.
I found a technet blog article the said it was possible to have PowerShell use C# code.
Article: Using CSharp (C#) code in Powershell scripts
I found the format I need to get the C# code to work in PowerShell, but if it don't pass the Main method an argument ([namespace.class]::Main(foo)) the script throws an error.
Is there a way I can pass a string of "on" or "off" to the main method, then depending on which string is passed run an if statement? If this is possible can you provide examples and/or links?
Below is the way I'm currently trying to structure my code.
$Assem = #( //assemblies go here)
$source = #"
using ...;
namespace AlertsOnOff
{
public class onOff
{
public static void Main(string[] args )
{
if(args == on)
{//post foo }
if(arge == off)
{ //post bar }
}
"#
Add-Type -TypeDefinition $Source -ReferencedAssumblies $Assem
[AlertsOnOff.onOff]::Main(off)
#PowerShell script code goes here.
[AlertsOnOff.onOff]::Main(on)
Well to start, if you are going to compile and run C# code, you need to write valid C# code. On the PowerShell side, if you invoke Main from PowerShell, you need to pass it an argument. PowerShell will automatically put a single argument into an array for you, but it won't insert an argument if you don't have one. That said, its not clear why this is in a Main method. It's not an executable. It could very well just have two static methods, TurnOn and TurnOff. The code below compiles and runs, modify as you see fit:
$source = #"
using System;
namespace AlertsOnOff
{
public class onOff
{
public static void Main(string[] args)
{
if(args[0] == `"on`")
{
Console.WriteLine(`"foo`");
}
if(args[0] == `"off`")
{
Console.WriteLine(`"bar`");
}
}
}
}
"#
Add-Type -TypeDefinition $Source
[AlertsOnOff.onOff]::Main("off")
# Other code here
[AlertsOnOff.onOff]::Main("on")
I've added Selenium WebDriver to the Powershell and create WebDriver instance:
Add-Type -path C:\Windows\net40\WebDriver.dll
$driver = New-Object OpenQA.Selenium.Firefox.FirefoxDriver
$driver.Url = "https://www.google.com"
Now I want to find input field:
$singleRecord = ($driver.FindElementByCssSelector("input.gbqfif"))
I found several examples how to "Test if element is present" in C#:
Selenium WebDriver - Test if element is present
Selenium c# Webdriver: Wait Until Element is Present
There is also guide here:
IWebDriver driver = new FirefoxDriver();
driver.Url = "http://somedomain/url_that_delays_loading";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
{
return d.FindElement(By.Id("someDynamicElement"));
});
but I cannot create something similar in Powershell, and almost all my tests fails because it takes time for page to load elements.
I'm not familiar with this API but if you're having problems getting it to work in PowerShell but it works in C#, then just create C# wrappers around the functionality you need that you can access from PowerShell. You can do this fairly easily with the Add-Type command. From the first example in its doc page:
$source = #"
public class BasicTest {
public static int Add(int a, int b) {
return (a + b);
}
public int Multiply(int a, int b) {
return (a * b);
}
}
"#
Add-Type -TypeDefinition $source
[BasicTest]::Add(4, 3)
$basicTestObject = New-Object BasicTest
$basicTestObject.Multiply(5, 2)
As you find C# code for this API that does work, you can plop it into a C# wrapper class that you can call from PowerShell. The key is to avoid features PowerShell can't handle like C# static extension methods.
The only really safe way is:
static bool isElementPresent(dynamic element, By by)
{
try
{
element.FindElement(by);
return true;
}
catch (NoSuchElementException e)
{
return false;
}
}
This method accept both, an IWebDriver or an IWebElement, as a starting point for FindElement().
And so you can us it on a LINQ Query:
_infodeskSectionContracts = from contract in
_infodeskSection.FindElements(By.CssSelector(_base + " * ul.list.type-itemlist li"))
select new Contract
{
element = contract.FindElement(By.TagName("a")),
label = contract.FindElement(By.TagName("h4")).Text,
contractNumber = (isElementPresent(contract, By.TagName("p")) ? contract.FindElement(By.TagName("p")).Text : "0000")
};
i'm french sorry for my english,
I try convert my c# code to python but i have a problem with this one.
I have found a class event for code python at this address : http://www.voidspace.org.uk/python/weblog/arch_d7_2007_02_03.shtml#e616
I would try implement this one in my python code.
My C# code :
// using
...
public abstract class SocketBase
{
public delegate void _onConnected();
public event _onConnected OnConnected;
public SocketBase()
{
...
}
public void TestEvent()
{
OnConnected();
}
}
public class SocketClient : SocketBase
{
public SocketClient()
{
base.OnConnected += Connected;
base.TestEvent();
}
public void Connected()
{
// print
}
}
And my python code :
from EventHook import *
class SocketBase(object):
def __init__(self):
self.onConnected = EventHook()
def TestEvent(self)
self.onConnected.fire()
class SocketClient(SocketBase):
def __init__(self):
SocketBase.__init__(self)
# How to access at the base class event from the child class ?
SocketBase.onConnected += self.Connected
SocketBase.TestEvent(self)
def Connected(self):
print "Connected :) !"
Can you help me please ?
Quentin.
Your SocketClient __init__ and def TestEvent indentation are off, that may be causing you some grief. Then, I see you're using python 2.7 so you may want to refactor your inheritance with the super method. This may also be how you want to access the parent methods and attributes.
from EventHook import *
class SocketBase(object):
def __init__(self):
self.onConnected = EventHook()
def test_event(self)
self.onConnected.fire()
class SocketClient(SocketBase):
def __init__(self):
super(SocketBase).__init__(self)
self.onConnected += self.connected # don't know what eventhook() returns
self.test_event()
def connected(self):
print "Connected :) !"
s = SocketClient()
Because python is dynamically typed different style conventions help distinguish between types. pep8
Thank you but i have no choice, i am obliged to use python 2.2 :x
So, i had tried your code but the python compiler said "TypeError: super() argument 1 must be type, not SocketClient" then i tried like this :
super(SocketClient, self).__init__()
It's work but my onConnected variable has not available, then i have try this :
from EventHook import *
class SocketBase(object):
on_connected = EventHook()
def __init__(self):
pass
def test_event(self):
self.on_connected.fire()
class SocketClient(SocketBase):
def __init__(self):
super(SocketClient, self).__init__()
self.on_connected += self.Connected
self.test_event()
def Connected(self):
print "Connected :) !"
s = SocketClient()
Output :
Connected :) !
Thank for your help.
I want to use msscript.ocx to call VBScript from C#, and allow the VBScript code to call back to functions in the C# program.
For example, in the following VBScript code, Clicktext is a custom C# function in the same clsss that is using msscript.ocx to run the VBScript.
For i=0 to i=4
Clicktext("Auto")
Next
The Clicktext function shoud be called 5 times.
Is there any way to do it?
This ComVisible console application with a reference to Interop.MSScriptControl:
// !! http://sandsprite.com/blogs/index.php?uid=11&pid=83
using System;
using MSScriptControl;
//class test has to support IDispatch to AddObject(). So make the assembly ComVisible
//via AssemblyInfo.cs or [assembly: System.Runtime.InteropServices.ComVisible(true)]
namespace MsScTest {
public class CsHelper {
public int increment(int y) { return ++y; }
}
class Program {
public static MSScriptControl.ScriptControl sc = new ScriptControl();
static void Main(string[] args) {
sc.Language = "VBScript";
sc.AddObject("CsHelper", new CsHelper(), true);
sc.AddCode(#"
Function inc(n)
inc = CsHelper.increment(n)
End Function
MsgBox inc(4711), 0, 'With a little help from my friend CsHelper'
".Replace("'", "\""));
return;
}
}
}
pudding:
---------------------------
With a little help from my friend CsHelper
---------------------------
4712
---------------------------
OK
---------------------------
demonstrates how to call a method of a C# object from VBScript code added to a MSScriptControl.