Public/New-CimSessionDown.ps1

<#
.SYNOPSIS
Opens a CIM session to a computer, with a fallback from WSMAN to DCOM for older operating systems.
 
.DESCRIPTION
CIM is the preferred method of interacting with WMI on a computer. It can reuse a single session instead of creaing a new session for each interaction. It can timeout which the built-in WMI functions will not. When communicating with modern operating systems it is less chatty with a fraction of the number of network roundtrips.
 
A New-CimSession by default only attempts a WSMAN connection, which is the modern CIM protocol. By using New-CimSessionDown instead existing connections can be re-used, and an additional check is done to use DCOM if WSMAN fails. This allows you to use CIM to communicate with all of your Windows estate without building two sets of CIM and WMI calls.
 
You should always specify -OperationTimeoutSec on any Get-CimInstance and related calls over a CimSession.
 
.PARAMETER ComputerName
The name of the remote computer(s). This parameter accepts pipeline input. The local computer is the default.
 
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the current user.
 
It's not possible to tell connections apart by credential, so, multiple connections to one server with different users is not recommended, as the wrong session may be returned.
 
.EXAMPLE
New-CimSessionDown -ComputerName Server1
New-CimSessionDown -ComputerName Server1, Server2
 
Creates a session to a server, then re-retrieves that existing session, along with a new one.
 
.INPUTS
String
 
.OUTPUTS
Microsoft.Management.Infrastructure.CimSession
 
.NOTES
The "Down" in New-CimSessionDown stands for "down-level", because it talks to down-level versions of Windows.
 
Verbose is always explicitly disabled on the New-CimSession call because it returns a useless message of ''.
 
This function is based largely on work done by Mike F Robbins @ http://mikefrobbins.com
 
#>


function New-CimSessionDown {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias("Name")]
        [ValidateNotNullorEmpty()]
        [string[]] $ComputerName = $env:COMPUTERNAME,
        [PSCredential] $Credential,
        [switch] $Fresh,
        $OperationTimeoutSec = 30 # "Robust connection timeout minimum is 180" but that's too long
    )

    begin {
        $dcomSessionOption = New-CimSessionOption -Protocol Dcom

        $verboseSplat = @{
            Verbose = $false
        }

        $sessionSplat = @{
            Verbose             = $false
            OperationTimeoutSec = $OperationTimeoutSec
        }

        if ($Credential) {
            $sessionSplat.Credential = $Credential
        }
    }

    Process {
        foreach ($computer in $ComputerName) {
            try {
                $computer = (Resolve-DnsName $computer)[0].Name
            } catch {
                Write-Verbose "Unable to resolve $computer FQDN"
            }
            $cimSession = $null

            # Heaven help me, sometimes I found multiple connections already
            if (!$Fresh -and ($cimSession = Get-CimSession | Where-Object { $_.ComputerName -eq $computer } | Select-Object -First 1)) {
                Write-Verbose "Used existing connection to $computer using the $($cimSession.Protocol) protocol."
                $cimSession
            } else {
                try {
                    if ((Test-WSMan -ComputerName $computer @verboseSplat).productversion -match 'Stack: (.*)') {
                        $version = [version] $Matches[1]

                        # v3 can connect to v2 but it can't query CIM reliably over it
                        if ($version.Major -ge 3) {
                            $cimSession = New-CimSession -ComputerName $computer @sessionSplat
                            Write-Verbose "Connected to $computer using the WSMAN protocol."
                            $cimSession
                        } else {
                            Write-Verbose "Failed to connect to $computer with WSMAN protocol because the version is too low"
                        }
                    }
                } catch {
                    Write-Verbose "Failed to connect to $computer with WSMAN protocol: $_"
                }

                if (!$cimSession) {
                    try {
                        New-CimSession -ComputerName $computer @sessionSplat -SessionOption $dcomSessionOption
                        Write-Verbose "Connected to $computer using the DCOM protocol."
                        $cimSession
                    } catch {
                        Write-Error "Failed to connect to $computer with DCOM protocol: $_"
                    }
                }
            }
        }
    }

    end {
    }
}