modules/Utilities/private/New-PSRemotingSession.ps1

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

function New-PSRemotingSession {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [System.String[]]$ComputerName,

        [Parameter(Mandatory = $false)]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty,

        [Parameter(Mandatory = $false)]
        [Switch]$Force
    )

    try {
        # ensure that WinRM service is running on the local machine
        $serviceState = Get-Service -Name 'WinRm'
        if($serviceState.Status -ine 'Running'){
            $msg = "WinRM Service is currently {0}. Ensure that service is running and try again." -f $serviceState.Status
            throw New-Object System.Exception($msg)
        }

        $remoteSessions = [System.Collections.ArrayList]::new()

        # return a list of current sessions on the computer
        # return only the sessions that are opened and available as this will allow new sessions to be opened
        # without having to wait for existing sessions to move from Busy -> Available
        $currentActiveSessions = Get-PSSession -Name "SdnDiag-*" | Where-Object {$_.State -ieq 'Opened' -and $_.Availability -ieq 'Available'}

        foreach($obj in $ComputerName){
            $session = $null

            # determine if an IP address was passed for the destination
            # if using IP address it needs to be added to the trusted hosts
            $isIpAddress = ($obj -as [IPAddress]) -as [Bool]
            if($isIpAddress){
                "{0} is an ip address" -f $obj | Trace-Output -Level:Verbose
                $trustedHosts = Get-Item -Path "WSMan:\localhost\client\TrustedHosts"
                if($trustedHosts.Value -notlike "*$obj*" -and $trustedHosts.Value -ne "*") {
                    "Adding {0} to {1}" -f $obj, $trustedHosts.PSPath | Trace-Output
                    Set-Item -Path "WSMan:\localhost\client\TrustedHosts" -Value $obj -Concatenate
                }
            }

            # check to see if session is already opened
            # if no session already exists or Force is defined, then create a new remote session
            if($currentActiveSessions.ComputerName -contains $obj -and !$Force){
                $session = ($currentActiveSessions | Where-Object {$_.ComputerName -eq $obj})[0]
                "Located existing powershell session {0}" -f $session.Name | Trace-Output -Level:Verbose
            }
            else {
                try {
                    if($Credential -ne [System.Management.Automation.PSCredential]::Empty){
                        "PSRemotingSession use provided credential {0}" -f $Credential.UserName | Trace-Output -Level:Verbose
                        $session = New-PSSession -Name "SdnDiag-$(Get-Random)" -ComputerName $obj -Credential $Credential -SessionOption (New-PSSessionOption -Culture en-US -UICulture en-US) -ErrorAction Stop
                    }
                    else {
                        # if we need to create a new remote session, need to check to ensure that if using an IP Address that credentials are specified
                        # which is a requirement from a WinRM perspective. Will throw a warning and skip session creation for this computer.
                        if ($isIpAddress -and $Credential -eq [System.Management.Automation.PSCredential]::Empty) {
                            "Unable to create PSSession to {0}. The Credential parameter is required when using an IP Address." -f $obj | Trace-Output -Level:Warning
                            continue
                        }

                        "PSRemotingSession use default credential" | Trace-Output -Level:Verbose
                        $session = New-PSSession -Name "SdnDiag-$(Get-Random)" -ComputerName $obj -SessionOption (New-PSSessionOption -Culture en-US -UICulture en-US) -ErrorAction Stop
                    }

                    "Created powershell session {0} to {1}" -f $session.Name, $obj | Trace-Output -Level:Verbose
                }
                catch {
                    "Unable to create powershell session to {0}`n`t{1}" -f $obj, $_.Exception | Trace-Output -Level:Warning
                    continue
                }
            }

            # add the session to the array
            if($session){
                [void]$remoteSessions.Add($session)
            }
        }

        return $remoteSessions

    }
    catch {
        "{0}`n{1}" -f $_.Exception, $_.ScriptStackTrace | Trace-Output -Level:Error
    }
}