Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
405 views
in Technique[技术] by (71.8m points)

method invocation - Powershell function call changing passed string into int

So I am using the kind of buggy Sapien powershell studio to make a powershell driven GUI application, and I am attempting to perform an ADSI query.

$nameOfDeviceInput is a System.Windows.Forms.TextBox

On one form, I have the following function:

$buttonPerformAction_Click={
    if (FindInAD($nameOfDeviceInput.Text).Count -gt 0)
    {
        $buttonPerformAction.BackColor = 'Red'
        $buttonPerformAction.Text = "System already exists in AD with that name. Try another name"
        return
    }
.....
}

On the "main" form, I have the function FindInAD

function FindInAd($nameOfSystem)
{
    Write-Host "seeking system" $nameOfSystem
    ([adsisearcher]"(CN=$nameOfSystem)").FindAll()
}

FindInAd() is failing because for whatever reason, $nameOfSystem is set to 1, and if I don't explicitly cast it as a string, it gets implicitly cast to Int32 (obviously)

I have tried the following:

Fully qualifying the textbox input by notating the form it belongs to ( $adObjectModifier )

 $buttonPerformAction_Click={
        if (FindInAD($adObjectModifier.$nameOfDeviceInput.Text).Count -gt 0)
        {
            $buttonPerformAction.BackColor = 'Red'
            $buttonPerformAction.Text = "System already exists in AD with that name. Try another name"
            return
        }
    .....
    }

Explicitly casting the $nameOfSystem parameter as a type of [string]

function FindInAd([string]$nameOfSystem)
{
    Write-Host "seeking system" $nameOfSystem
    ([adsisearcher]"(CN=$nameOfSystem)").FindAll()
}

Passing a raw string into FindInAD from the AdObjectModifier form.

.... 

if (FindInAD("Test").Count -gt 0)

....

There is nothing else on the output pipeline at the time, (at least not from me) in between the method invocation. It is EventHandler > Function Call with String parameter

Why are the strings I'm passing getting changed to a digit???

EDIT: I think my passed parameter is being automatically replaced with the resulting boolean somehow, but this doesn't make any sense to me....

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your have a syntax problem:

FindInAD($nameOfDeviceInput.Text).Count # WRONG

Note: Wrong in this context means: the syntax is formally valid, but doesn't do what you expect - see the bottom section.

It should be:

(FindInAD $nameOfDeviceInput.Text).Count

PowerShell commands - functions, cmdlets, scripts and external programs - are invoked like shell commands - foo arg1 arg2 - and not like C# methods - foo('arg1', 'arg2').

That is:

  • Do not put (...) around the list of arguments.

    • However, you do need (...) around the call as a whole if you want a command call to participate in an expression, as shown above with the access to property .Count - see this answer for more information.
  • Separate arguments with whitespace (at least one space), both from each other and from the command name - do not use ,

    • , between arguments functions differently: It constructs an array that is passed as a single argument - see below.
  • You may pass simple strings (ones that contain neither spaces nor PowerShell metacharacters such as ; or &) as barewords; that is, quoting them is optional; e.g., instead of foo 'bar', you can call foo bar - see this answer for how PowerShell parses unquoted command arguments.

  • Also, if a target function or script has explicitly declared parameters (which binary cmdlets invariably do), such as -bar and -baz, you can pass your values as named arguments, i.e. by prepending them with the target parameter name; doing so is good practice in scripts: foo -bar arg1 -baz arg2

By contrast, calling methods of objects uses the syntax familiar from regular programming languages such as C# ($obj.foo('arg1', 'arg2'))

This difference relates two PowerShell's two fundamental parsing modes, explained in detail in this answer:

  • Commands are parsed in argument mode - as in shells.

  • Method calls and operator-based expressions are parsed in expression mode - as in regular programming languages.

These modes are required in order to allow PowerShell serve double duty: as a shell on the one hand, and as a scripting (programming) language on the other.


PowerShell can help you avoid this syntax problem:

Note that the problem isn't that using method syntax to call a command is invalid syntax, but that it doesn't work as intended, which can be difficult to diagnose.

In short: When you call command foo as foo('foo', 'bar'), ('foo', 'bar')is a 2-element array, which is then passed to foo as a single argument.

To prevent the problem to begin with, you can set Set-StrictMode to -Version 2 or higher, which makes PowerShell report an error if you accidentally use method syntax when calling a command:

# Turn on the check for accidental method syntax.
# Note: This also turns on ADDITIONAL checks - see below.
Set-StrictMode -Version 2

# This call now produces an ERROR, because the proper syntax would be:
#    foo 'a' 'b'
foo('a', 'b')

Caveats:

  • Set-StrictMode -Version 2 comprises additional strictness checks that you must then also conform to, notably:

    • You must not reference non-existent variables.
    • You must not reference non-existent properties; see GitHub issue #2798 for an associated pitfall in connection with PowerShell's unified handling of scalars and collections.
  • An error is reported only for pseudo method calls with multiple arguments (e.g.,
    foo('bar', 'baz')), not with only one; e.g., foo('bar') is accepted, because the single-argument case generally still (accidentally) works.

  • The errors reported for strictness violations are statement-terminating errors: that is, they only terminate the statement at hand, but by default the script continues; to ensure that overall execution aborts - on any type of error - you'd have to set
    $ErrorActionPreference = 'Stop' at the start of your code. See this answer for more information.


As for what you tried:

FindInAD($nameOfDeviceInput.Text).Count

is the same as:

FindInAD ($nameOfDeviceInput.Text).Count

That is, the result of expression ($nameOfDeviceInput.Text).Count is passed as an argument to function FindInAD.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...