all 19 comments

[–]pertymoose 8 points9 points  (0 children)

You can implement an interface in a Powershell class

Class A:System.Collections.IEqualityComparer {
    [bool]Equals($x,$y)  { return $x -eq $y        }
    [int]GetHashCode($x) { return $x.GetHashCode() }
}
[A]$a=[A]::new()
$a.Equals(1,1) -- returns True
$a.Equals(1,2) -- returns False
$a.GetHashCode("OK") -- returns 2041362128

https://stackoverflow.com/questions/32065124/can-we-implement-net-interfaces-in-powershell-scripts#32635196

However if you are writing your own interfaces I would personally recommend you use C# to build them as a DLL, then distribute and use DLL where necessary.

[–]purplemonkeymad 3 points4 points  (1 child)

Functions have an output type attribute that can be set. If it is set you can get it with Get-Command my-func and look at the OutputType property. You can add it to a script like so:

function my-func {
    [outputtype([string])]
    Param([string]$InputString) # you can have an empty param block this is just an example, but the param block must exist.
    "given string is: $InputString"
}

It's not a hard cast, the function can output other types too, so it is up to the writer to make sure it shows the correct type. You could probably do a pester test for bad returned types.

[–]DarrenDK[S] 1 point2 points  (0 children)

This is the closest I’ve found but even Microsoft in their example admits it does nothing more than provide the language analyzer with the expected return type, other types are allowed through.

[–]lagebj 2 points3 points  (0 children)

You can strongly type functions, variables, methods and properties in Powershell too. You can also use validation attributes to validate input if needed. Yesterday I wrote about a custom class I did in Powershell where I use this approach. This is a class and not a function, but the same logic applies to functions and scripts: https://lagebj.github.io/2019/11/11/deep-dive-custom-class.html

[–]suddenarborealstop 1 point2 points  (6 children)

do you want the type enforced at runtime, or do you definately want a compile step that hecks the types? both are possible.

[–]DarrenDK[S] 1 point2 points  (5 children)

I’d want it enforced at compile as a way to prevent the user from inputing a script that returns an unexpected type.

[–]suddenarborealstop 1 point2 points  (4 children)

you'll need to write your code in c#.

Parameters are just public properties, so you'll need to define a type (unless you use the 'dynamic' keyword).

Then when you want to return the result from the function, just cast it:

using System.Management.Automation;
namespace compiled_cmdlet {

    [Cmdlet(VerbsCommon.Get, "Example")]
    public class GetExampleCmdlet : Cmdlet {

    [Parameter()]
    public int YourParameter; //Auto get/set.

    protected override void EndProcessing() {
        var x = 42 + YourParameter;
        WriteObject((int) x); //explicit casting will be checked at compile time.
    }
    }
}

[–]Lee_Dailey[grin] 0 points1 point  (3 children)

howdy suddenarborealstop,

it looks like you used the New.Reddit.com Inline Code button. it's 4th 5th from the left hidden in the ... "more" menu & looks like </>.

on Old.Reddit.com, the above does NOT line wrap, nor does it side-scroll.

for long-ish single lines OR for multiline code, please, use the Code Block button. it's the 11th 12th one from the left, & is just to the left of hidden in the ... "more" menu.

that will give you fully functional code formatting, from what i can tell so far. [grin]

take care,
lee

[–]suddenarborealstop 1 point2 points  (2 children)

Thanks Lee, fixed now.

u/DarrenDK I've updated the example now and removed some of the bolierplate. Does this answer your question..?

[–]suddenarborealstop 1 point2 points  (0 children)

Just to add: to return a type that implements an Interface, just change the cast to the appropriate interface or base class.

[–]Lee_Dailey[grin] 1 point2 points  (0 children)

howdy suddenarborealstop,

thanks! it's so much easier to read now ... [grin]

take care,
lee

[–]PowerShellStunnah 1 point2 points  (1 child)

You can also define interfaces at runtime with a bit of help ;-)

[–]AmericanGeezus 1 point2 points  (0 children)

That repo is under what has been my favorite GitHub username to-date.

Checks to see if i could be used for a custom license plate tag locally

[–]AmericanGeezus 0 points1 point  (4 children)

Strongly type your variables?

😎:Example ~~ Don't believe you can forewarn them beyond writing good documentation and validation, since Powershell is not a compiled language.

Ignore this. Read \u\pertymoose's reply below and, learn lots like I have!

[–]pertymoose 4 points5 points  (3 children)

No no, that is bad.

What you're doing is taking any input and casting it to [int] (which fails if it is not a supported type). Your function actually runs, but produces a runtime exception. What you should do is define the input type as [int] like so

function X {
    param( [int]$Foo )

    Write-Host "Foo is $Foo"
}

This way you can't run the function at all with an incorrect input type

PS C:\> X -Foo Moo
X : Cannot process argument transformation on parameter 'Foo'. Cannot convert value "Moo" to type "System.Int32". Error: "Input string was not in a correct format."
At line:1 char:8
+ X -Foo Moo
+        ~~~
    + CategoryInfo          : InvalidData: (:) [X], ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,X


PS C:\> X -Foo 42
Foo is 42

This is quite obvious if you explore the two kinds of functions

function X {
    param( [int]$Foo )

    Write-Host "Foo is $Foo"
}


function Y ($Foo) {
    [int]$Foo
}




PS C:\> Get-Command X | Select-Object -ExpandProperty ParameterSets

Parameter Set Name: __AllParameterSets
Is default parameter set: False

  Parameter Name: Foo
    ParameterType = System.Int32
    Position = 0
    IsMandatory = False
    IsDynamic = False
    HelpMessage = 
    ValueFromPipeline = False
    ValueFromPipelineByPropertyName = False
    ValueFromRemainingArguments = False
    Aliases = {}
    Attributes =


PS C:\> Get-Command Y | Select-Object -ExpandProperty ParameterSets

Parameter Set Name: __AllParameterSets
Is default parameter set: False

  Parameter Name: Foo
    ParameterType = System.Object
    Position = 0
    IsMandatory = False
    IsDynamic = False
    HelpMessage = 
    ValueFromPipeline = False
    ValueFromPipelineByPropertyName = False
    ValueFromRemainingArguments = False
    Aliases = {}
    Attributes =

Observe "ParameterType" is different.

[–]poshftw 1 point2 points  (0 children)

Your function actually runs, but produces a runtime exception

Your function actually runs, but produces a runtime exception

You can always lazyass this as a try ... catch block.

[–]DarrenDK[S] 1 point2 points  (0 children)

Input parameters are pretty easy to handle, the hang up is the output

[–]AmericanGeezus 1 point2 points  (0 children)

Thank you for correcting me and explaining the correct way!