Axel Williot
Axel Williot

Reputation: 505

Powershell function unexpectedly returns no object

I want to have in a .ps1 file some code that creates a PSSession that can be used in other .ps1 scripts (in order to avoid code duplication).

At first I thought i need a function that creates a PSSession and returns it but I am confused about how they the function outputs work.

Here is my function:

function newRemoteSession
{
    param([string]$ipAddress)

    $accountName = 'admin'
    $accountPassword = 'admin'
    $accountPasswordSecure = ConvertTo-SecureString $accountPassword -AsPlainText -Force
    $accountCredential = New-Object System.Management.Automation.PSCredential ($accountName, $accountPasswordSecure)

    Try
    {
        $remoteSession = New-PSSession -ComputerName $ipAddress -UseSSL -Credential $accountCredential -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck) -ErrorAction Stop
    }
    Catch [System.Management.Automation.RuntimeException] #PSRemotingTransportException
    {
        Write-Host 'Could not connect with default credentials. Please enter credentials...'    
        $remoteSession = New-PSSession -ComputerName $ipAddress -UseSSL -Credential (Get-Credential) -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck) -ErrorAction Stop
        Break
    }

    return $remoteSession
}

However when I call $s = newRemoteSession(192.168.1.10), $s is empty.

When I run a script with

Write-Host '00'
$s = newRemoteSession('192.168.1.10')
$s
Write-Host '02'

function newRemoteSession
{
        ........
    Write-Host '01'
    $remoteSession
}

I get only '00' in the console, but I know the function runs because I get the credential prompt.

EDIT:

Ok, now it works:

Upvotes: 2

Views: 80

Answers (1)

mklement0
mklement0

Reputation: 438208

You've found the problems yourself, but since they're common pitfalls, let me elaborate a little:

  • Only ever use break / continue inside a loop (for, foreach, while, do) or in the branch handlers of a switch statement.

    • Otherwise, PowerShell looks up the call stack for an enclosing loop and, in the absence of one, exits the script.

    • This is what happened with the break in your catch block.

  • Do not use (...) to enclose the list of function (command) arguments and do not separate arguments with ,:

    • In PowerShell, functions - just like cmdlets - are called with shell-like syntax, without parentheses and with whitespace-separated arguments (, is only used to construct an array to be passed as a single argument)[1] .

      # WRONG: method-invocation syntax does NOT apply to *functions*
      # (It *happens* to work *in this case*, however, because only a
      # a *single* argument is passed and the (...) is a no-op in this case,
      # but this syntax should never be used.)
      newRemoteSession('192.168.1.10')
      
      # OK: Shell-like syntax, which PowerShell calls *argument mode*:
      # Note that the argument needn't be quoted, because it 
      # contains no shell metacharacters.
      # If there were additional arguments, you'd separate them with *whitespace*
      newRemoteSession 192.168.1.10
      
      # BETTER: You can even use *parameter names* (again, as with cmdlets),
      # which helps readability.
      newRemoteSession -ipAddress 192.168.1.10
      
  • In PowerShell, functions must be defined before you can call them.

    • You initially didn't notice, because a previous definition of your newRemoteSession function happened to exist.

[1] For more information about PowerShell's two fundamental parsing modes - argument mode and expression mode - see this answer of mine.

Upvotes: 2

Related Questions