0

I want to call a PowerShell script with 3 arguments.

The first argument is the path of a C# script file.

Inside the PowerShell script, I want to execute a method in the C# script and also pass all the arguments to it.

# RunBackup.ps1
$csharp = Get-Content -Path $args[0]
$job = Start-Job -ScriptBlock {
    Add-Type -TypeDefinition "$csharp"
    $obj = New-Object Main
    $result = $obj.Execute($args)
    $result
}
Wait-Job $job
Receive-Job $job

// Main.cs
using System;

public class Main
{
    public int Execute(string[] args)
    {
        Console.WriteLine(args[0]);
        return 0;
    }
}

But when I run the PS script with ./RunBackup Main.cs 1 2 3, I got the following error.

Cannot bind argument to parameter 'TypeDefinition' because it is an empty string.
    + CategoryInfo          : InvalidData: (:) [Add-Type], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.AddTypeCommand
    + PSComputerName        : localhost
 
Cannot find type [Main]: verify that the assembly containing this type is loaded.
    + CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
    + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
    + PSComputerName        : localhost

You cannot call a method on a null-valued expression.
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
    + PSComputerName        : localhost
3
  • 3
    Why are you running the program that way? Make the class called 'Program` and the entrypoint function called Main, then compile the app. You will then either get an exe or dll, which you can then run with dotnet file.dll parameters Commented Feb 10, 2021 at 6:14
  • @LukeParker Thank you for the comment. I can change the class name, but will it allow me to run C# source code or do I still have to compile it? My requirement is to run the C# source code. Commented Feb 10, 2021 at 17:39
  • @LukeParker I realize I can use dotnet run app args, it'll build and run from source code. That'll meet my requirements. Thanks. Commented Feb 10, 2021 at 18:41

1 Answer 1

2

You're trying to access the $csharp variable, but it's not in scope within the child ScriptBlock, so it automagically gets set to $null as per PowerShell's default lax rules for variable initialization and reference. You can verify this by using Set-StrictMode to prevent and warn about this default behaviour:

$csharp = Get-Content -Path $args[0]
$job = Start-Job -ScriptBlock {
    Set-StrictMode -Version Latest

    Add-Type -TypeDefinition $csharp
    $obj = New-Object Main
    $result = $obj.Execute($args)
    $result
}
Wait-Job $job
Receive-Job $job

Output:

The variable '$csharp' cannot be retrieved because it has not been set.
    + CategoryInfo          : InvalidOperation: (csharp:String) [], RuntimeException
    + FullyQualifiedErrorId : VariableIsUndefined
    + PSComputerName        : localhost
 
Cannot find type [Main]: verify that the assembly containing this type is loaded.
    + CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
    + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
    + PSComputerName        : localhost
 
The variable '$obj' cannot be retrieved because it has not been set.
    + CategoryInfo          : InvalidOperation: (obj:String) [], RuntimeException
    + FullyQualifiedErrorId : VariableIsUndefined
    + PSComputerName        : localhost
 
The variable '$result' cannot be retrieved because it has not been set.
    + CategoryInfo          : InvalidOperation: (result:String) [], RuntimeException
    + FullyQualifiedErrorId : VariableIsUndefined
    + PSComputerName        : localhost

To fix, you need to explicitly pass the value of $csharp to the ScriptBlock:

$csharp = Get-Content -Path $args[0]
$job = Start-Job -ScriptBlock {
    Add-Type -TypeDefinition $input # powershell implicit param provided by InputObject
    $obj = New-Object Main
    $result = $obj.Execute($args)
    $result
} -InputObject $csharp
Wait-Job $job
Receive-Job $job

Of course, now you get different errors, but those are outside the scope of this question!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.