2

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:

  • The Break in the Catch was stopping everything.
  • The function call must be without parenthesis.
  • The second code was wrong because the function must be defined before the call.
mklement0
  • 382,024
  • 64
  • 607
  • 775
Axel Williot
  • 485
  • 6
  • 13
  • If you place the function in the same file where you are trying to call it does it work? – EBGreen Mar 01 '18 at 20:43
  • 4
    Run `$s = newRemoteSession '192.168.1.10'` **without parentheses**. – JosefZ Mar 01 '18 at 21:02
  • I get the same results with `$s = newRemoteSession '192.168.1.10' ` and with `$s = newRemoteSession -ipAddress '192.168.1.10'` – Axel Williot Mar 01 '18 at 21:06
  • The code that you posted should error the first time that it is run. – EBGreen Mar 01 '18 at 21:08
  • Also, if you get the prompt and you do not see the write host, then only a portion of the function code is running. – EBGreen Mar 01 '18 at 21:09
  • 1
    Try taking the qualifier off your catch block – EBGreen Mar 01 '18 at 21:15
  • 2
    Is your second block your complete script? the function needs to be defined before the call. As @JosefZ said, you also need to remove the parenthesis from the function call. Try writing your script in PowerShell_ISE if possible, then step through debugging. You also don't need the break in the `catch` block. – Matthew Wetmore Mar 01 '18 at 21:20
  • You do not trap `New-PSSession … -ErrorAction Stop` **inside** `Catch` block. – JosefZ Mar 01 '18 at 21:28
  • @JozefZ The Catch is for the first New-PSSession: if it fails (because wrong default credentials) I recall it with credential prompt. – Axel Williot Mar 01 '18 at 21:37

1 Answers1

2

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.

mklement0
  • 382,024
  • 64
  • 607
  • 775