Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 47 additions & 8 deletions src/SdnDiagnostics.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ New-Variable -Name 'SdnDiagnostics' -Scope 'Global' -Force -Value @{
# defines the current role(s) determined for the current node
# supported values are 'Common', 'Gateway', 'NetworkController', 'Server', 'LoadBalancerMux'
Role = @()

# when set to $true, PSRemoting sessions will use WinRM over HTTPS (port 5986 by default)
# configure this when CIS hardening or other security policies disable WinRM over HTTP
UseSSL = $false

# overrides the default WinRM port used when creating PSRemoting sessions
# if not set, defaults to 5985 (HTTP) or 5986 (HTTPS) based on UseSSL
Port = 0
}
}

Expand Down Expand Up @@ -751,7 +759,15 @@ function Start-SdnDataCollection {

[Parameter(Mandatory = $false, ParameterSetName = 'Role')]
[Parameter(Mandatory = $false, ParameterSetName = 'Computer')]
[bool]$ConvertETW = $true
[bool]$ConvertETW = $true,

[Parameter(Mandatory = $false, ParameterSetName = 'Role')]
[Parameter(Mandatory = $false, ParameterSetName = 'Computer')]
[Switch]$UseSSL,

[Parameter(Mandatory = $false, ParameterSetName = 'Role')]
[Parameter(Mandatory = $false, ParameterSetName = 'Computer')]
[System.Int32]$Port
)

# if we are running in a remote session, we need to do some extra validation
Expand All @@ -765,6 +781,16 @@ function Start-SdnDataCollection {
}
}

# if UseSSL or Port were explicitly provided, update the global config so that all downstream
# PSRemoting session creation functions pick up the correct transport settings
if ($PSBoundParameters.ContainsKey('UseSSL')) {
$Global:SdnDiagnostics.Config.UseSSL = $UseSSL.IsPresent
}

if ($PSBoundParameters.ContainsKey('Port')) {
$Global:SdnDiagnostics.Config.Port = $Port
}

$ErrorActionPreference = 'Continue'
$dataCollectionNodes = [System.Collections.ArrayList]::new() # need an arrayList so we can remove objects from this list

Expand Down Expand Up @@ -927,18 +953,31 @@ function Start-SdnDataCollection {

$Global:ProgressPreference = 'SilentlyContinue'
$nodesToRemove = [System.Collections.ArrayList]::new()
$tncScriptBlock = {
$tncResult = Test-NetConnection -ComputerName $_.Name -Port 5985 -InformationLevel Quiet
if (-NOT ($tncResult)) {
[void]$nodesToRemove.Add($_)
}
if ($Global:SdnDiagnostics.Config.Port -gt 0) {
$tncPort = $Global:SdnDiagnostics.Config.Port
}
elseif ($Global:SdnDiagnostics.Config.UseSSL) {
$tncPort = 5986
}
else {
$tncPort = 5985
}

if ($PSVersionTable.PSVersion.Major -ge 7) {
$dataCollectionNodes | Foreach-Object -ThrottleLimit 10 -Parallel $tncScriptBlock
$dataCollectionNodes | Foreach-Object -ThrottleLimit 10 -Parallel {
$tncResult = Test-NetConnection -ComputerName $_.Name -Port $using:tncPort -InformationLevel Quiet
if (-NOT ($tncResult)) {
[void]($using:nodesToRemove).Add($_)
}
}
}
else {
$dataCollectionNodes | ForEach-Object $tncScriptBlock
$dataCollectionNodes | ForEach-Object {
$tncResult = Test-NetConnection -ComputerName $_.Name -Port $tncPort -InformationLevel Quiet
if (-NOT ($tncResult)) {
[void]$nodesToRemove.Add($_)
}
}
}

if ($nodesToRemove.Count -gt 0) {
Expand Down
178 changes: 164 additions & 14 deletions src/modules/SdnDiag.Utilities.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,13 @@ function Copy-FileFromRemoteComputer {
[Switch]$Recurse,

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

[Parameter(Mandatory = $false)]
[Switch]$UseSSL,

[Parameter(Mandatory = $false)]
[System.Int32]$Port
)

try {
Expand All @@ -520,8 +526,25 @@ function Copy-FileFromRemoteComputer {
catch {
"{0}. Attempting to copy files using WinRM" -f $_ | Trace-Output -Level:Warning

$winRmParams = @{
Path = $Path
ComputerName = $object
Destination = $Destination
Force = $Force.IsPresent
Recurse = $Recurse.IsPresent
Credential = $Credential
}

if ($PSBoundParameters.ContainsKey('UseSSL')) {
$winRmParams.Add('UseSSL', $UseSSL)
}

if ($PSBoundParameters.ContainsKey('Port')) {
$winRmParams.Add('Port', $Port)
}

try {
Copy-FileFromRemoteComputerWinRM -Path $Path -ComputerName $object -Destination $Destination -Force:($Force.IsPresent) -Recurse:($Recurse.IsPresent) -Credential $Credential
Copy-FileFromRemoteComputerWinRM @winRmParams
}
catch {
# Catch the copy failed exception to not stop the copy for other computers which might success
Expand Down Expand Up @@ -673,10 +696,29 @@ function Copy-FileFromRemoteComputerWinRM {
[Switch]$Recurse,

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

[Parameter(Mandatory = $false)]
[Switch]$UseSSL,

[Parameter(Mandatory = $false)]
[System.Int32]$Port
)

$session = New-PSRemotingSession -ComputerName $ComputerName -Credential $Credential
$sessionParams = @{
ComputerName = $ComputerName
Credential = $Credential
}

if ($PSBoundParameters.ContainsKey('UseSSL')) {
$sessionParams.Add('UseSSL', $UseSSL)
}

if ($PSBoundParameters.ContainsKey('Port')) {
$sessionParams.Add('Port', $Port)
}

$session = New-PSRemotingSession @sessionParams
if ($session) {
foreach ($subPath in $Path) {
"Copying {0} to {1} using WinRM Session {2}" -f $subPath, $Destination.FullName, $session.Name | Trace-Output
Expand Down Expand Up @@ -729,7 +771,13 @@ function Copy-FileToRemoteComputer {
[Switch]$Recurse,

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

[Parameter(Mandatory = $false)]
[Switch]$UseSSL,

[Parameter(Mandatory = $false)]
[System.Int32]$Port
)

try {
Expand All @@ -754,8 +802,25 @@ function Copy-FileToRemoteComputer {
catch {
"{0}. Attempting to copy files using WinRM" -f $_ | Trace-Output -Level:Warning

$winRmParams = @{
Path = $Path
ComputerName = $object
Destination = $Destination
Credential = $Credential
Force = $Force.IsPresent
Recurse = $Recurse.IsPresent
}

if ($PSBoundParameters.ContainsKey('UseSSL')) {
$winRmParams.Add('UseSSL', $UseSSL)
}

if ($PSBoundParameters.ContainsKey('Port')) {
$winRmParams.Add('Port', $Port)
}

try {
Copy-FileToRemoteComputerWinRM -Path $Path -ComputerName $object -Destination $Destination -Credential $Credential -Force:($Force.IsPresent) -Recurse:($Recurse.IsPresent)
Copy-FileToRemoteComputerWinRM @winRmParams
}
catch {
# Catch the copy failed exception to not stop the copy for other computers which might success
Expand Down Expand Up @@ -904,10 +969,29 @@ function Copy-FileToRemoteComputerWinRM {
[Switch]$Recurse,

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

[Parameter(Mandatory = $false)]
[Switch]$UseSSL,

[Parameter(Mandatory = $false)]
[System.Int32]$Port
)

$session = New-PSRemotingSession -ComputerName $ComputerName -Credential $Credential
$sessionParams = @{
ComputerName = $ComputerName
Credential = $Credential
}

if ($PSBoundParameters.ContainsKey('UseSSL')) {
$sessionParams.Add('UseSSL', $UseSSL)
}

if ($PSBoundParameters.ContainsKey('Port')) {
$sessionParams.Add('Port', $Port)
}

$session = New-PSRemotingSession @sessionParams
if ($session) {
# copy the files to the destination using WinRM
foreach ($subPath in $Path) {
Expand Down Expand Up @@ -1558,7 +1642,13 @@ function Invoke-PSRemoteCommand {
[System.String]$Activity,

[Parameter(Mandatory = $false, ParameterSetName = 'AsJob')]
[int]$ExecutionTimeout = 900
[int]$ExecutionTimeout = 900,

[Parameter(Mandatory = $false)]
[Switch]$UseSSL,

[Parameter(Mandatory = $false)]
[System.Int32]$Port
)

$params = @{
Expand All @@ -1574,6 +1664,14 @@ function Invoke-PSRemoteCommand {
$psSessionParams.Add('ImportModuleOnRemoteSession', $ImportModuleOnRemoteSession)
}

if ($PSBoundParameters.ContainsKey('UseSSL')) {
$psSessionParams.Add('UseSSL', $UseSSL)
}

if ($PSBoundParameters.ContainsKey('Port')) {
$psSessionParams.Add('Port', $Port)
}

$session = New-PSRemotingSession @psSessionParams
if ($session) {
$params.Add('Session', $session)
Expand Down Expand Up @@ -1847,13 +1945,34 @@ function New-PSRemotingSession {
[System.String]$ModuleName = $Global:SdnDiagnostics.Config.ModuleName,

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

[Parameter(Mandatory = $false)]
[Switch]$UseSSL,

[Parameter(Mandatory = $false)]
[System.Int32]$Port
)

begin {
[bool]$disableSeeding = $Global:SdnDiagnostics.Config.DisableModuleSeeding
[bool]$importModuleOnRemoteSession = $Global:SdnDiagnostics.Config.ImportModuleOnRemoteSession

# if UseSSL was not explicitly provided, fall back to global config
if (-NOT $PSBoundParameters.ContainsKey('UseSSL')) {
$UseSSL = [bool]$Global:SdnDiagnostics.Config.UseSSL
}

# set the default port based on whether SSL is being used, then check global config override
if (-NOT $PSBoundParameters.ContainsKey('Port')) {
if ($Global:SdnDiagnostics.Config.Port -gt 0) {
$Port = $Global:SdnDiagnostics.Config.Port
}
else {
$Port = if ($UseSSL) { 5986 } else { 5985 }
}
}

$importRemoteModule = {
param([string]$arg0, $arg1, $arg2)
try {
Expand Down Expand Up @@ -1910,8 +2029,9 @@ function New-PSRemotingSession {

# determine if an IP address was passed for the destination
# if using IP address it needs to be added to the trusted hosts
# when UseSSL is enabled, TrustedHosts management is not required as the server identity is validated via certificate
$isIpAddress = ($objectName -as [IPAddress]) -as [Bool]
if ($isIpAddress) {
if ($isIpAddress -and -NOT $UseSSL) {
try {
Confirm-IsAdmin

Expand All @@ -1929,9 +2049,38 @@ function New-PSRemotingSession {
}

try {
$newPSSessionParams = @{
Name = "SdnDiag-$(Get-Random)"
ComputerName = $objectName
Port = $Port
ErrorAction = 'Stop'
}

# Build session options only with parameters supported by the current platform
# WinRM-specific parameters (Culture, UICulture, IdleTimeout) are only available on Windows
$psSessionOptionCmd = Get-Command New-PSSessionOption -ErrorAction SilentlyContinue
if ($psSessionOptionCmd) {
$sessionOptionParams = @{}
if ($psSessionOptionCmd.Parameters.ContainsKey('IdleTimeout')) {
$sessionOptionParams['IdleTimeout'] = 86400000
}
if ($psSessionOptionCmd.Parameters.ContainsKey('Culture')) {
$sessionOptionParams['Culture'] = 'en-US'
$sessionOptionParams['UICulture'] = 'en-US'
}
if ($sessionOptionParams.Count -gt 0) {
$newPSSessionParams.Add('SessionOption', (New-PSSessionOption @sessionOptionParams))
}
}

if ($UseSSL) {
$newPSSessionParams.Add('UseSSL', $true)
"PSRemotingSession will use SSL on port {0}" -f $Port | Trace-Output -Level:Verbose
}

if ($Credential -ne [System.Management.Automation.PSCredential]::Empty) {
"PSRemotingSession use user-defined credential" | Trace-Output -Level:Verbose
$session = New-PSSession -Name "SdnDiag-$(Get-Random)" -ComputerName $objectName -Credential $Credential -SessionOption (New-PSSessionOption -Culture en-US -UICulture en-US -IdleTimeout 86400000) -ErrorAction Stop
$newPSSessionParams.Add('Credential', $Credential)
}
else {
# if the credential is not defined, we want to check if we
Expand All @@ -1941,14 +2090,15 @@ function New-PSRemotingSession {

# 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) {
if ($isIpAddress -and -NOT $UseSSL -and $Credential -eq [System.Management.Automation.PSCredential]::Empty) {
throw New-Object System.NotSupportedException("Unable to create PSSession to $objectName. The Credential parameter is required when using an IP Address.")
}

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

$session = New-PSSession @newPSSessionParams

"Created powershell session {0} to {1}" -f $session.Name, $objectName | Trace-Output -Level:Verbose
if ($ImportModuleOnRemoteSession) {
"Importing module {0} on remote session {1}" -f $ModuleName, $session.Name | Trace-Output -Level:Verbose
Expand Down
Loading