diff --git a/.azure-pipelines/Official.yml b/.azure-pipelines/Official.yml deleted file mode 100644 index 472f0f0b..00000000 --- a/.azure-pipelines/Official.yml +++ /dev/null @@ -1,93 +0,0 @@ -trigger: - branches: - include: - - main - paths: - include: - - src - -parameters: # parameters are shown up in ADO UI in a build queue time -- name: 'debug' - displayName: 'Enable debug output' - type: boolean - default: false - -variables: - CDP_DEFINITION_BUILD_COUNT: $[counter('', 0)] # needed for onebranch.pipeline.version task - system.debug: ${{ parameters.debug }} - ENABLE_PRS_DELAYSIGN: 1 - ROOT: $(Build.SourcesDirectory) - REPOROOT: $(Build.SourcesDirectory) - OUTPUTROOT: $(REPOROOT)\out - NUGET_XMLDOC_MODE: none - WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest' # Docker image which is used to build the project - -resources: - repositories: - - repository: templates - type: git - name: OneBranch.Pipelines/GovernedTemplates - ref: refs/heads/main - -extends: - template: v2/OneBranch.Official.CrossPlat.yml@templates - parameters: - globalSdl: - tsa: - enabled: false - binskim: - break: true - policheck: - break: true - - stages: - - stage: build - jobs: - - job: main - pool: - type: windows - - variables: - ob_outputDirectory: '$(REPOROOT)\out' - ob_sdl_binskim_break: true - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main') }}: - ob_symbolsPublishing_enabled: true - ob_artifactBaseName: 'drop' - - steps: - - task: PowerShell@2 - displayName: "Create custom version" - inputs: - filepath: '$(Build.SourcesDirectory)\.build\generate-version.ps1' - - - task: onebranch.pipeline.version@1 - displayName: 'Setup BuildNumber' - inputs: - system: 'Custom' - customVersion: '$(CUSTOM_VERSION)' - - - task: PowerShell@2 - displayName: 'Restore external dependencies' - inputs: - filePath: '$(Build.SourcesDirectory)\.build\restore.ps1' - workingDirectory: '$(Build.SourcesDirectory)' - - - task: PowerShell@2 - displayName: 'Generate SdnDiagnostics module files' - inputs: - filePath: '$(Build.SourcesDirectory)\.build\generate-sdndiagnostics.ps1' - - - task: PowerShell@2 - displayName: 'Generate module manifest for SdnDiagnostics' - inputs: - filePath: '$(Build.SourcesDirectory)\.build\generate-module-manifest.ps1' - arguments: -Manifest $(Build.SourcesDirectory)\out\build\SdnDiagnostics\SdnDiagnostics.psd1 -Version $(CUSTOM_VERSION) - - - task: onebranch.pipeline.signing@1 - displayName: 'Script Signing' - inputs: - command: 'sign' - signing_environment: 'azure-ado' - signing_profile: 'external_distribution' - files_to_sign: '**/*.exe;**/*.dll;**/*.ps1;**/*.psm1;**/*.psd1;**/*.js' - search_root: '$(Build.SourcesDirectory)\out' diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..1e2bffd5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + + - package-ecosystem: nuget + directory: / + schedule: + interval: daily diff --git a/.github/workflows/build-pipeline.yml b/.github/workflows/build-pipeline.yml index 76b2a27b..d20708c3 100644 --- a/.github/workflows/build-pipeline.yml +++ b/.github/workflows/build-pipeline.yml @@ -14,6 +14,9 @@ on: workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel +permissions: + contents: read + jobs: # This workflow contains a single job called "build" build: @@ -22,8 +25,13 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: + - name: Harden Runner + uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 + with: + egress-policy: audit + - name: 'Checkout SdnDiagnostics' - uses: actions/checkout@v2 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: path: main diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 00000000..7141d093 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,27 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, +# surfacing known-vulnerable versions of the packages declared or updated in the PR. +# Once installed, if the workflow run is marked as required, +# PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 + with: + egress-policy: audit + + - name: 'Checkout Repository' + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - name: 'Dependency Review' + uses: actions/dependency-review-action@0c155c5e8556a497adf53f2c18edabf945ed8e70 # v4.3.2 diff --git a/.github/workflows/powershell.yml b/.github/workflows/powershell.yml index 210c5558..5a7630be 100644 --- a/.github/workflows/powershell.yml +++ b/.github/workflows/powershell.yml @@ -29,7 +29,12 @@ jobs: name: PSScriptAnalyzer runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Harden Runner + uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 + with: + egress-policy: audit + + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Run PSScriptAnalyzer uses: microsoft/psscriptanalyzer-action@6b2948b1944407914a58661c49941824d149734f @@ -44,6 +49,6 @@ jobs: # Upload the SARIF file generated in the previous step - name: Upload SARIF results file - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@9fdb3e49720b44c48891d036bb502feb25684276 # v3.25.6 with: sarif_file: results.sarif diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml new file mode 100644 index 00000000..9bf6f845 --- /dev/null +++ b/.github/workflows/scorecards.yml @@ -0,0 +1,76 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '20 7 * * 2' + push: + branches: ["main"] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + contents: read + actions: read + + steps: + - name: Harden Runner + uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 + with: + egress-policy: audit + + - name: "Checkout code" + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 + with: + results_file: results.sarif + results_format: sarif + # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecards on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + + # Public repositories: + # - Publish results to OpenSSF REST API for easy access by consumers + # - Allows the repository to include the Scorecard badge. + # - See https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories: + # - `publish_results` will always be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@9fdb3e49720b44c48891d036bb502feb25684276 # v3.25.6 + with: + sarif_file: results.sarif diff --git a/.github/workflows/server2019-sdntest-pr.yml b/.github/workflows/server2019-sdntest-pr.yml index 8f0d691e..812a696f 100644 --- a/.github/workflows/server2019-sdntest-pr.yml +++ b/.github/workflows/server2019-sdntest-pr.yml @@ -15,6 +15,9 @@ on: workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel +permissions: + contents: read + jobs: # This workflow contains a single job called "build" build-and-test: @@ -23,6 +26,11 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: + - name: Harden Runner + uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 + with: + egress-policy: audit + - name: Cleanup existing files run: | Remove-Item -Path .\* -Recurse -Force -Verbose @@ -30,7 +38,7 @@ jobs: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout SdnDiagnostics repo - uses: actions/checkout@v2 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/server2019-sdntest.yml b/.github/workflows/server2019-sdntest.yml index 8c6959db..54d5be3e 100644 --- a/.github/workflows/server2019-sdntest.yml +++ b/.github/workflows/server2019-sdntest.yml @@ -15,6 +15,9 @@ on: workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel +permissions: + contents: read + jobs: # This workflow contains a single job called "build" build-and-test: @@ -23,6 +26,11 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: + - name: Harden Runner + uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0 + with: + egress-policy: audit + - name: Cleanup existing files run: | Remove-Item -Path .\* -Recurse -Force -Verbose @@ -30,7 +38,7 @@ jobs: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout SdnDiagnostics repo - uses: actions/checkout@v2 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: ref: main diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..cba08601 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +repos: +- repo: https://github.com/gitleaks/gitleaks + rev: v8.16.3 + hooks: + - id: gitleaks +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace diff --git a/README.md b/README.md index 6733cd32..41eb33fe 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/microsoft/SdnDiagnostics/badge)](https://scorecard.dev/viewer/?uri=github.com/microsoft/SdnDiagnostics) ![](https://github.com/microsoft/SdnDiagnostics/actions/workflows/dependency-review.yml/badge.svg) ![](https://github.com/microsoft/SdnDiagnostics/actions/workflows/powershell.yml/badge.svg) + # Project SdnDiagnostics is a PowerShell module that is designed to simplify the diagnostic troubleshooting and data collection process when troubleshooting issues related to [Microsoft Software Defined Network](https://docs.microsoft.com/en-us/windows-server/networking/sdn/software-defined-networking). @@ -9,14 +11,6 @@ Please refer to the [wiki](https://github.com/microsoft/SdnDiagnostics/wiki) on | PowerShell Gallery | [![downloads](https://img.shields.io/powershellgallery/dt/SdnDiagnostics.svg?label=Downloads)](https://www.powershellgallery.com/packages/SdnDiagnostics) | [![downloads](https://img.shields.io/powershellgallery/v/SdnDiagnostics.svg?label=Version)](https://www.powershellgallery.com/packages/SdnDiagnostics) | | NuGet | [![downloads](https://img.shields.io/nuget/dt/SdnDiagnostics.svg?label=Downloads)](https://www.nuget.org/packages/SdnDiagnostics) |[![downloads](https://img.shields.io/nuget/v/SdnDiagnostics.svg?label=Version)](https://www.nuget.org/packages/SdnDiagnostics) -## GitHub Action Status -| Actions | Current Status | -| :-- | :-- | -| Build Validation | ![](https://github.com/microsoft/SdnDiagnostics/actions/workflows/server2019-sdntest.yml/badge.svg) | -| Build Pipeline | ![](https://github.com/microsoft/SdnDiagnostics/actions/workflows/build-pipeline.yml/badge.svg) | -| Script Analyzer | ![](https://github.com/microsoft/SdnDiagnostics/actions/workflows/powershell.yml/badge.svg) | - - # Contributing This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us @@ -33,8 +27,8 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio To get started on contributing to this module, refer to the [contributing](https://github.com/microsoft/SdnDiagnostics/blob/main/.github/contributing.md) guide on this project. # Trademarks -This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft -trademarks or logos is subject to and must follow +This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft +trademarks or logos is subject to and must follow [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies. diff --git a/src/SdnDiagnostics.psd1 b/src/SdnDiagnostics.psd1 index 030b8d02..9c339123 100644 --- a/src/SdnDiagnostics.psd1 +++ b/src/SdnDiagnostics.psd1 @@ -96,6 +96,7 @@ 'Get-SdnResource', 'Get-SdnServer', 'Get-SdnServerCertificate', + 'Get-SdnServiceFabricApplication', 'Get-SdnServiceFabricApplicationHealth', 'Get-SdnServiceFabricClusterConfig', 'Get-SdnServiceFabricClusterHealth', diff --git a/src/modules/SdnDiag.Common/private/Get-CommonConfigState.ps1 b/src/modules/SdnDiag.Common/private/Get-CommonConfigState.ps1 index a9db45ee..0c5a890e 100644 --- a/src/modules/SdnDiag.Common/private/Get-CommonConfigState.ps1 +++ b/src/modules/SdnDiag.Common/private/Get-CommonConfigState.ps1 @@ -12,7 +12,7 @@ function Get-CommonConfigState { $currentErrorActionPreference = $ErrorActionPreference $ProgressPreference = 'SilentlyContinue' - $ErrorActionPreference = 'SilentlyContinue' + $ErrorActionPreference = 'Ignore' try { [System.IO.FileInfo]$OutputDirectory = Join-Path -Path $OutputDirectory.FullName -ChildPath "Common" @@ -47,14 +47,22 @@ function Get-CommonConfigState { Get-NetAdapterHardwareInfo | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-NetAdapterHardwareInfo' -FileType txt -Format Table netsh winhttp show proxy | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'netsh_winhttp_show_proxy' -FileType txt - $outputDir = New-Item -Path (Join-Path -Path $OutputDirectory.FullName -ChildPath 'NetAdapter') -ItemType Directory -Force - foreach($adapter in Get-NetAdapter){ - Get-NetAdapter -Name $adapter.Name | Export-ObjectToFile -FilePath $outputDir.FullName -Prefix $adapter.Name -Name 'Get-NetAdapter' -FileType txt -Format List - Get-NetAdapterSriov -Name $adapter.Name -ErrorAction $ErrorActionPreference | Export-ObjectToFile -FilePath $outputDir.FullName -Prefix $adapter.Name -Name 'Get-NetAdapterSriov' -FileType txt -Format List - Get-NetAdapterRsc -Name $adapter.Name -ErrorAction $ErrorActionPreference | Export-ObjectToFile -FilePath $outputDir.FullName -Prefix $adapter.Name -Name 'Get-NetAdapterRsc' -FileType txt -Format List - Get-NetAdapterHardwareInfo -Name $adapter.Name -ErrorAction $ErrorActionPreference | Export-ObjectToFile -FilePath $outputDir.FullName -Prefix $adapter.Name -Name 'Get-NetAdapterHardwareInfo' -FileType txt -Format List - Get-NetAdapterAdvancedProperty -Name $adapter.Name ` - | Export-ObjectToFile -FilePath $outputDir.FullName -Prefix $adapter.Name -Name 'Get-NetAdapterAdvancedProperty' -FileType txt -Format List + $netAdapter = Get-NetAdapter + if ($netAdapter) { + $netAdapterRootDir = New-Item -Path (Join-Path -Path $OutputDirectory.FullName -ChildPath 'NetAdapter') -ItemType Directory -Force + + $netAdapter | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-NetAdapter' -FileType txt -Format List + $netAdapter | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-NetAdapter' -FileType json + $netAdapter | ForEach-Object { + $prefix = $_.Name.ToString().Replace(' ','_').Trim() + $_ | Get-NetAdapterAdvancedProperty | Export-ObjectToFile -FilePath $netAdapterRootDir.FullName -Prefix $prefix -Name 'Get-NetAdapterAdvancedProperty' -FileType json + $_ | Get-NetAdapterBinding | Export-ObjectToFile -FilePath $netAdapterRootDir.FullName -Prefix $prefix -Name 'Get-NetAdapterBinding' -FileType json + $_ | Get-NetAdapterChecksumOffload -ErrorAction $ErrorActionPreference | Export-ObjectToFile -FilePath $netAdapterRootDir.FullName -Prefix $prefix -Name 'Get-NetAdapterChecksumOffload' -FileType json + $_ | Get-NetAdapterHardwareInfo -ErrorAction $ErrorActionPreference | Export-ObjectToFile -FilePath $netAdapterRootDir.FullName -Prefix $prefix -Name 'Get-NetAdapterHardwareInfo' -FileType json + $_ | Get-NetAdapterRsc -ErrorAction $ErrorActionPreference | Export-ObjectToFile -FilePath $netAdapterRootDir.FullName -Prefix $prefix -Name 'Get-NetAdapterRsc' -FileType json + $_ | Get-NetAdapterSriov -ErrorAction $ErrorActionPreference | Export-ObjectToFile -FilePath $netAdapterRootDir.FullName -Prefix $prefix -Name 'Get-NetAdapterSriov' -FileType json + $_ | Get-NetAdapterStatistics -ErrorAction $ErrorActionPreference | Export-ObjectToFile -FilePath $netAdapterRootDir.FullName -Prefix $prefix -Name 'Get-NetAdapterStatistics' -FileType json + } } # Gather DNS client settings diff --git a/src/modules/SdnDiag.Common/public/Start-SdnDataCollection.ps1 b/src/modules/SdnDiag.Common/public/Start-SdnDataCollection.ps1 index db6acf1f..05dfbf32 100644 --- a/src/modules/SdnDiag.Common/public/Start-SdnDataCollection.ps1 +++ b/src/modules/SdnDiag.Common/public/Start-SdnDataCollection.ps1 @@ -102,19 +102,22 @@ function Start-SdnDataCollection { [bool]$ConvertETW = $true ) + $dataCollectionNodes = [System.Collections.ArrayList]::new() # need an arrayList so we can remove objects from this list + $filteredDataCollectionNodes = @() $stopWatch = [System.Diagnostics.Stopwatch]::StartNew() $dataCollectionObject = [PSCustomObject]@{ DurationInMinutes = $null - TotalSize = $null - OutputDirectory = $null - Role = $null - IncludeNetView = $IncludeNetView - IncludeLogs = $IncludeLogs - FromDate = $FromDate.ToString() - FromDateUTC = $FromDate.ToUniversalTime().ToString() - ToDate = $ToDate.ToString() - ToDateUTC = $ToDate.ToUniversalTime().ToString() + TotalSize = $null + OutputDirectory = $null + Role = $null + IncludeNetView = $IncludeNetView + IncludeLogs = $IncludeLogs + FromDate = $FromDate.ToString() + FromDateUTC = $FromDate.ToUniversalTime().ToString() + ToDate = $ToDate.ToString() + ToDateUTC = $ToDate.ToUniversalTime().ToString() + Result = $null } $collectLogSB = { @@ -142,9 +145,6 @@ function Start-SdnDataCollection { [System.IO.FileInfo]$workingDirectory = (Get-WorkingDirectory) [System.IO.FileInfo]$tempDirectory = "$(Get-WorkingDirectory)\Temp" - $dataCollectionNodes = @() - $filteredDataCollectionNodes = @() - # setup the directory location where files will be saved to "Starting SDN Data Collection" | Trace-Output @@ -190,7 +190,7 @@ function Start-SdnDataCollection { } "{0} with role {1} added for data collection" -f $object.Name, $object.Role | Trace-Output - $dataCollectionNodes += $object + [void]$dataCollectionNodes.Add($object) } } } @@ -205,28 +205,64 @@ function Start-SdnDataCollection { } "{0} with role {1} added for data collection" -f $object.Name, $object.Role | Trace-Output - $dataCollectionNodes += $object + [void]$dataCollectionNodes.Add($object) } } } } - if ($null -eq $dataCollectionNodes) { + if ($dataCollectionNodes.Count -eq 0) { throw New-Object System.NullReferenceException("No data nodes identified") } + # once we have identified the nodes, we need to validate WinRM connectivity to the nodes + # if we are running on PowerShell 7 or greater, we can leverage the -Parallel parameter + # to speed up the process + # if we are running on PowerShell 5.1, we will need to run the process in serial + # if we have any nodes that fail the WinRM connectivity test, we will remove them from the data collection + "Validating WinRM connectivity to {0}" -f ($dataCollectionNodes.Name -join ', ') | Trace-Output + + $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 ($PSVersionTable.PSVersion.Major -ge 7) { + $dataCollectionNodes | Foreach-Object -ThrottleLimit 10 -Parallel $tncScriptBlock + } + else { + $dataCollectionNodes | ForEach-Object $tncScriptBlock + } + + if ($nodesToRemove.Count -gt 0) { + $nodesToRemove | ForEach-Object { + "Removing {0} from data collection due to WinRM connectivity issues" -f $_.Name | Trace-Output -Level:Warning + [void]$dataCollectionNodes.Remove($_) + } + } + $Global:ProgressPreference = 'Continue' + $dataCollectionNodes = $dataCollectionNodes | Sort-Object -Property Name -Unique $groupedObjectsByRole = $dataCollectionNodes | Group-Object -Property Role # ensure SdnDiagnostics installed across the data nodes and versions are the same - Install-SdnDiagnostics -ComputerName $NetworkController -ErrorAction Stop - Install-SdnDiagnostics -ComputerName $dataCollectionNodes.Name -ErrorAction Stop - - # collect control plane information without regardless of roles defined - $slbStateInfo = Get-SdnSlbStateInformation -NcUri $sdnFabricDetails.NcUrl -Credential $NcRestCredential - $slbStateInfo | ConvertTo-Json -Depth 100 | Out-File "$($OutputDirectory.FullName)\SlbState.Json" - Invoke-SdnResourceDump -NcUri $sdnFabricDetails.NcUrl -OutputDirectory $OutputDirectory.FullName -Credential $NcRestCredential - Get-SdnNetworkControllerState -NetworkController $NetworkController -OutputDirectory $OutputDirectory.FullName -Credential $Credential -NcRestCredential $NcRestCredential + # depending on the state of the environment though, these may result in failure + Install-SdnDiagnostics -ComputerName $NetworkController -ErrorAction Continue + Install-SdnDiagnostics -ComputerName $dataCollectionNodes.Name -ErrorAction Continue + + # ensure that the NcUrl is populated before we start collecting data + # in scenarios where certificate is not trusted or expired, we will not be able to collect data + if (-NOT ([System.String]::IsNullOrEmpty($sdnFabricDetails.NcUrl))) { + $slbStateInfo = Get-SdnSlbStateInformation -NcUri $sdnFabricDetails.NcUrl -Credential $NcRestCredential + $slbStateInfo | ConvertTo-Json -Depth 100 | Out-File "$($OutputDirectory.FullName)\SlbState.Json" + Invoke-SdnResourceDump -NcUri $sdnFabricDetails.NcUrl -OutputDirectory $OutputDirectory.FullName -Credential $NcRestCredential + Get-SdnNetworkControllerState -NetworkController $NetworkController -OutputDirectory $OutputDirectory.FullName -Credential $Credential -NcRestCredential $NcRestCredential + } + Get-SdnNetworkControllerClusterInfo -NetworkController $NetworkController -OutputDirectory $OutputDirectory.FullName -Credential $Credential $debugInfraHealthResults = Get-SdnFabricInfrastructureResult if ($debugInfraHealthResults) { @@ -332,7 +368,7 @@ function Start-SdnDataCollection { } } - if ($diagLogNetShare) { + if ($diagLogNetShare -and $IncludeLogs) { $isNetShareMapped = New-SdnDiagNetworkMappedShare -NetworkSharePath $diagLogNetShare -Credential $Credential if ($isNetShareMapped) { $outputDir = Join-Path -Path $OutputDirectory.FullName -ChildPath 'NetShare_SdnDiagnosticLogs' @@ -387,31 +423,55 @@ function Start-SdnDataCollection { Copy-FileFromRemoteComputer -Path (Get-TraceOutputFile) -Destination $formattedDirectoryName.FullName -ComputerName $node -Credential $Credential -Force } - # check for any failed PS remoting jobs and copy them to data collection - if (Test-Path -Path "$(Get-WorkingDirectory)\PSRemoteJob_Failures") { - Copy-Item -Path "$(Get-WorkingDirectory)\PSRemoteJob_Failures" -Destination $formattedDirectoryName.FullName -Recurse - } - - "Performing cleanup of {0} across the SDN fabric" -f $tempDirectory.FullName | Trace-Output - Clear-SdnWorkingDirectory -Path $tempDirectory.FullName -Recurse -ComputerName $filteredDataCollectionNodes -Credential $Credential - $dataCollectionObject.TotalSize = (Get-FolderSize -Path $OutputDirectory.FullName -Total) $dataCollectionObject.OutputDirectory = $OutputDirectory.FullName $dataCollectionObject.Role = $groupedObjectsByRole.Name + $dataCollectionObject.Result = 'Success' + } + catch { + $_ | Trace-Exception + $_ | Write-Error + $dataCollectionObject.Result = 'Failed' + } + finally { + $stopWatch.Stop() + $dataCollectionObject.DurationInMinutes = $stopWatch.Elapsed.TotalMinutes - # remove any completed or failed jobs - Remove-SdnDiagnosticJob -State @('Completed', 'Failed') + try { + "Performing post operations and cleanup of {0} across the SDN fabric" -f $tempDirectory.FullName | Trace-Output - $stopwatch.Stop() - $dataCollectionObject.DurationInMinutes = $stopWatch.Elapsed.TotalMinutes - $dataCollectionObject | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'SdnDataCollection_Summary' -FileType json -Depth 4 - "`Data collection completed. Logs have been saved to {0}" -f $OutputDirectory.FullName | Trace-Output -Level:Success - Copy-Item -Path (Get-TraceOutputFile) -Destination $OutputDirectory.FullName + # check for any failed PS remoting jobs and copy them to data collection + if (Test-Path -Path "$(Get-WorkingDirectory)\PSRemoteJob_Failures") { + Copy-Item -Path "$(Get-WorkingDirectory)\PSRemoteJob_Failures" -Destination $formattedDirectoryName.FullName -Recurse + } + + if ($filteredDataCollectionNodes) { + Clear-SdnWorkingDirectory -Path $tempDirectory.FullName -Recurse -ComputerName $filteredDataCollectionNodes -Credential $Credential + } - return $dataCollectionObject + # remove any completed or failed jobs + Remove-SdnDiagnosticJob -State @('Completed', 'Failed') + } + catch { + $_ | Trace-Exception + Write-Error -Message "An error occurred during cleanup of the SDN fabric." -Exception $_.Exception + $dataCollectionObject.Result = 'Failed' + } } - catch { - $stopwatch.Stop() - $_ | Trace-Exception + + $dataCollectionObject | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'SdnDataCollection_Summary' -FileType json -Depth 4 -ErrorAction Continue + Copy-Item -Path (Get-TraceOutputFile) -Destination $OutputDirectory.FullName -Force -ErrorAction Continue + + # we will return the object to the caller regardless if the data collection was successful or not + $msg = "Sdn Data Collection completed with status of {0}" -f $dataCollectionObject.Result + switch ($dataCollectionObject.Result) { + 'Success' { + $msg | Trace-Output + } + 'Failed' { + $msg | Trace-Output -Level:Error + } } + + return $dataCollectionObject } diff --git a/src/modules/SdnDiag.Gateway/private/Get-GatewayConfigState.ps1 b/src/modules/SdnDiag.Gateway/private/Get-GatewayConfigState.ps1 index 2e38be21..36b5623b 100644 --- a/src/modules/SdnDiag.Gateway/private/Get-GatewayConfigState.ps1 +++ b/src/modules/SdnDiag.Gateway/private/Get-GatewayConfigState.ps1 @@ -16,7 +16,7 @@ function Get-GatewayConfigState { $currentErrorActionPreference = $ErrorActionPreference $ProgressPreference = 'SilentlyContinue' - $ErrorActionPreference = 'SilentlyContinue' + $ErrorActionPreference = 'Ignore' try { $config = Get-SdnModuleConfiguration -Role 'Gateway' diff --git a/src/modules/SdnDiag.Health/private/Test-NcHostAgentConnectionToApiService.ps1 b/src/modules/SdnDiag.Health/private/Test-NcHostAgentConnectionToApiService.ps1 index 25ad2814..93b08bef 100644 --- a/src/modules/SdnDiag.Health/private/Test-NcHostAgentConnectionToApiService.ps1 +++ b/src/modules/SdnDiag.Health/private/Test-NcHostAgentConnectionToApiService.ps1 @@ -42,7 +42,7 @@ function Test-NcHostAgentConnectionToApiService { # get the current primary replica of Network Controller # if we cannot return the primary replica, then something is critically wrong with Network Controller # in which case we should mark this test as failed and return back to the caller with guidance to fix the SlbManagerService - $primaryReplicaNode = Get-SdnServiceFabricReplica -NetworkController $SdnEnvironmentObject.EnvironmentInfo.NetworkController -ServiceTypeName 'ApiService' -Credential $NcRestCredential -Primary + $primaryReplicaNode = Get-SdnServiceFabricReplica -NetworkController $SdnEnvironmentObject.EnvironmentInfo.NetworkController[0] -ServiceTypeName 'ApiService' -Credential $Credential -Primary if ($null -ieq $primaryReplicaNode) { "Unable to return primary replica of ApiService" | Trace-Output -Level:Error $sdnHealthObject.Result = 'FAIL' diff --git a/src/modules/SdnDiag.Health/private/Test-NcUrlNameResolution.ps1 b/src/modules/SdnDiag.Health/private/Test-NcUrlNameResolution.ps1 index 0f59bf50..3162cc1d 100644 --- a/src/modules/SdnDiag.Health/private/Test-NcUrlNameResolution.ps1 +++ b/src/modules/SdnDiag.Health/private/Test-NcUrlNameResolution.ps1 @@ -21,7 +21,7 @@ function Test-NcUrlNameResolution { try { "Validate that the Network Controller NB API URL resolves to the correct IP address" | Trace-Output - $ncApiReplicaPrimary = Get-SdnServiceFabricReplica -NetworkController $SdnEnvironmentObject.ComputerName -Credential $Credential -ServiceTypeName 'ApiService' -Primary + $ncApiReplicaPrimary = Get-SdnServiceFabricReplica -NetworkController $SdnEnvironmentObject.ComputerName[0] -Credential $Credential -ServiceTypeName 'ApiService' -Primary if ($null -eq $ncApiReplicaPrimary) { "Unable to find the primary replica for the ApiService" | Trace-Output -Level:Warning return $sdnHealthObject diff --git a/src/modules/SdnDiag.Health/private/Test-ServiceFabricApplicationHealth.ps1 b/src/modules/SdnDiag.Health/private/Test-ServiceFabricApplicationHealth.ps1 index 982e1220..eae8e105 100644 --- a/src/modules/SdnDiag.Health/private/Test-ServiceFabricApplicationHealth.ps1 +++ b/src/modules/SdnDiag.Health/private/Test-ServiceFabricApplicationHealth.ps1 @@ -20,12 +20,12 @@ function Test-ServiceFabricApplicationHealth { try { "Validating the Service Fabric Application Health for Network Controller" | Trace-Output - $ncNodes = Get-SdnServiceFabricNode -NetworkController $SdnEnvironmentObject.ComputerName -Credential $credential + $ncNodes = Get-SdnServiceFabricNode -NetworkController $SdnEnvironmentObject.ComputerName[0] -Credential $credential if($null -eq $ncNodes){ throw New-Object System.NullReferenceException("Unable to retrieve service fabric nodes") } - $applicationHealth = Get-SdnServiceFabricApplicationHealth -NetworkController $SdnEnvironmentObject.ComputerName -Credential $Credential + $applicationHealth = Get-SdnServiceFabricApplicationHealth -NetworkController $SdnEnvironmentObject.ComputerName[0] -Credential $Credential if ($applicationHealth.AggregatedHealthState -ine 'Ok') { $sdnHealthObject.Result = 'FAIL' $sdnHealthObject.Remediation += "Examine the Service Fabric Application Health for Network Controller to determine why the health is not OK." diff --git a/src/modules/SdnDiag.Health/private/Test-ServiceFabricClusterHealth.ps1 b/src/modules/SdnDiag.Health/private/Test-ServiceFabricClusterHealth.ps1 index e4114f3f..5e6dfee5 100644 --- a/src/modules/SdnDiag.Health/private/Test-ServiceFabricClusterHealth.ps1 +++ b/src/modules/SdnDiag.Health/private/Test-ServiceFabricClusterHealth.ps1 @@ -20,12 +20,12 @@ function Test-ServiceFabricClusterHealth { try { "Validating the Service Fabric Cluster Health for Network Controller" | Trace-Output - $ncNodes = Get-SdnServiceFabricNode -NetworkController $SdnEnvironmentObject.ComputerName -Credential $credential + $ncNodes = Get-SdnServiceFabricNode -NetworkController $SdnEnvironmentObject.ComputerName[0] -Credential $credential if($null -eq $ncNodes){ throw New-Object System.NullReferenceException("Unable to retrieve service fabric nodes") } - $clusterHealth = Get-SdnServiceFabricClusterHealth -NetworkController $SdnEnvironmentObject.ComputerName -Credential $Credential + $clusterHealth = Get-SdnServiceFabricClusterHealth -NetworkController $SdnEnvironmentObject.ComputerName[0] -Credential $Credential if ($clusterHealth.AggregatedHealthState -ine 'Ok') { $sdnHealthObject.Result = 'FAIL' $sdnHealthObject.Remediation += "Examine the Service Fabric Cluster Health for Network Controller to determine why the health is not OK." diff --git a/src/modules/SdnDiag.Health/private/Test-ServiceFabricNodeStatus.ps1 b/src/modules/SdnDiag.Health/private/Test-ServiceFabricNodeStatus.ps1 index 26b14d06..1e28599d 100644 --- a/src/modules/SdnDiag.Health/private/Test-ServiceFabricNodeStatus.ps1 +++ b/src/modules/SdnDiag.Health/private/Test-ServiceFabricNodeStatus.ps1 @@ -20,7 +20,7 @@ function Test-ServiceFabricNodeStatus { try { "Validating the Service Fabric Nodes for Network Controller" | Trace-Output - $ncNodes = Get-SdnServiceFabricNode -NetworkController $SdnEnvironmentObject.ComputerName -Credential $credential + $ncNodes = Get-SdnServiceFabricNode -NetworkController $SdnEnvironmentObject.ComputerName[0] -Credential $credential if($null -eq $ncNodes){ throw New-Object System.NullReferenceException("Unable to retrieve service fabric nodes") } diff --git a/src/modules/SdnDiag.Health/private/Test-ServiceFabricPartitionDatabaseSize.ps1 b/src/modules/SdnDiag.Health/private/Test-ServiceFabricPartitionDatabaseSize.ps1 index 9fca4b76..d2165390 100644 --- a/src/modules/SdnDiag.Health/private/Test-ServiceFabricPartitionDatabaseSize.ps1 +++ b/src/modules/SdnDiag.Health/private/Test-ServiceFabricPartitionDatabaseSize.ps1 @@ -21,14 +21,17 @@ function Test-ServiceFabricPartitionDatabaseSize { try { "Validate the size of the Service Fabric Partition Databases for Network Controller services" | Trace-Output - $ncNodes = Get-SdnServiceFabricNode -NetworkController $SdnEnvironmentObject.ComputerName -Credential $credential + $ncNodes = Get-SdnServiceFabricNode -NetworkController $SdnEnvironmentObject.ComputerName[0] -Credential $credential if($null -eq $ncNodes){ throw New-Object System.NullReferenceException("Unable to retrieve service fabric nodes") } foreach($node in $ncNodes){ - $ncApp = Invoke-SdnServiceFabricCommand -NetworkController $SdnEnvironmentObject.ComputerName -Credential $Credential -ScriptBlock { + $ncApp = Invoke-SdnServiceFabricCommand -NetworkController $SdnEnvironmentObject.ComputerName[0] -Credential $Credential -ScriptBlock { param([Parameter(Position = 0)][String]$param1) + + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null Get-ServiceFabricDeployedApplication -ApplicationName 'fabric:/NetworkController' -NodeName $param1 } -ArgumentList @($node.NodeName.ToString()) @@ -38,10 +41,10 @@ function Test-ServiceFabricPartitionDatabaseSize { } # Only stateful service have the database file - $ncServices = Get-SdnServiceFabricService -NetworkController $SdnEnvironmentObject.ComputerName -Credential $Credential | Where-Object {$_.ServiceKind -eq "Stateful"} + $ncServices = Get-SdnServiceFabricService -NetworkController $SdnEnvironmentObject.ComputerName[0] -Credential $Credential | Where-Object {$_.ServiceKind -eq "Stateful"} foreach ($ncService in $ncServices){ - $replica = Get-SdnServiceFabricReplica -NetworkController $SdnEnvironmentObject.ComputerName -ServiceName $ncService.ServiceName -Credential $Credential | Where-Object {$_.NodeName -eq $node.NodeName} + $replica = Get-SdnServiceFabricReplica -NetworkController $SdnEnvironmentObject.ComputerName[0] -ServiceName $ncService.ServiceName -Credential $Credential | Where-Object {$_.NodeName -eq $node.NodeName} $imosStorePath = Join-Path -Path $ncAppWorkDir -ChildPath "P_$($replica.PartitionId)\R_$($replica.ReplicaId)\ImosStore" $imosStoreFile = Invoke-PSRemoteCommand -ComputerName $node.NodeName -Credential $Credential -ScriptBlock { param([Parameter(Position = 0)][String]$param1) diff --git a/src/modules/SdnDiag.Health/private/Test-SlbManagerConnectionToMux.ps1 b/src/modules/SdnDiag.Health/private/Test-SlbManagerConnectionToMux.ps1 index 0145c829..3526a90c 100644 --- a/src/modules/SdnDiag.Health/private/Test-SlbManagerConnectionToMux.ps1 +++ b/src/modules/SdnDiag.Health/private/Test-SlbManagerConnectionToMux.ps1 @@ -42,7 +42,7 @@ function Test-SlbManagerConnectionToMux { # get the current primary replica of Network Controller # if we cannot return the primary replica, then something is critically wrong with Network Controller # in which case we should mark this test as failed and return back to the caller with guidance to fix the SlbManagerService - $primaryReplicaNode = Get-SdnServiceFabricReplica -NetworkController $SdnEnvironmentObject.EnvironmentInfo.NetworkController -ServiceTypeName 'SlbManagerService' -Credential $NcRestCredential -Primary + $primaryReplicaNode = Get-SdnServiceFabricReplica -NetworkController $SdnEnvironmentObject.EnvironmentInfo.NetworkController[0] -ServiceTypeName 'SlbManagerService' -Credential $NcRestCredential -Primary if ($null -ieq $primaryReplicaNode) { "Unable to return primary replica of SlbManagerService" | Trace-Output -Level:Error $sdnHealthObject.Result = 'FAIL' diff --git a/src/modules/SdnDiag.Health/public/Debug-SdnFabricInfrastructure.ps1 b/src/modules/SdnDiag.Health/public/Debug-SdnFabricInfrastructure.ps1 index b7235bb9..5cc2f5ce 100644 --- a/src/modules/SdnDiag.Health/public/Debug-SdnFabricInfrastructure.ps1 +++ b/src/modules/SdnDiag.Health/public/Debug-SdnFabricInfrastructure.ps1 @@ -22,7 +22,7 @@ function Debug-SdnFabricInfrastructure { param ( [Parameter(Mandatory = $false, ParameterSetName = 'Role')] [Parameter(Mandatory = $false, ParameterSetName = 'ComputerName')] - [System.String]$NetworkController = $(HostName), + [System.String]$NetworkController = $env:COMPUTERNAME, [Parameter(Mandatory = $false, ParameterSetName = 'Role')] [ValidateSet('Gateway', 'NetworkController', 'Server', 'LoadBalancerMux')] @@ -47,16 +47,18 @@ function Debug-SdnFabricInfrastructure { $script:SdnDiagnostics_Health.Cache = $null $aggregateHealthReport = @() - try { - if (-NOT ($PSBoundParameters.ContainsKey('NetworkController'))) { - $config = Get-SdnModuleConfiguration -Role 'NetworkController' - $confirmFeatures = Confirm-RequiredFeaturesInstalled -Name $config.windowsFeature - if (-NOT ($confirmFeatures)) { - "The current machine is not a NetworkController, run this on NetworkController or use -NetworkController parameter to specify one" | Trace-Output -Level:Warning - return # don't throw exception, since this is a controlled scenario and we do not need stack exception tracing - } + # check to see if we are running in a remote session and if so, ensure we have the necessary credentials + # otherwise we will not be able to perform the necessary tests + if ($PSSenderInfo) { + if ($Credential -eq [System.Management.Automation.PSCredential]::Empty -or $null -eq $Credential) { + throw New-Object System.NotSupportedException("This operation is not supported in a remote session without supplying -Credential.") } + } + if (Test-ComputerNameIsLocal -ComputerName $NetworkController) { + Confirm-IsNetworkController + } + try { $environmentInfo = Get-SdnInfrastructureInfo -NetworkController $NetworkController -Credential $Credential -NcRestCredential $NcRestCredential if($null -eq $environmentInfo){ throw New-Object System.NullReferenceException("Unable to retrieve environment details") diff --git a/src/modules/SdnDiag.LoadBalancerMux/private/Get-SlbMuxConfigState.ps1 b/src/modules/SdnDiag.LoadBalancerMux/private/Get-SlbMuxConfigState.ps1 index 1abe3588..5e873396 100644 --- a/src/modules/SdnDiag.LoadBalancerMux/private/Get-SlbMuxConfigState.ps1 +++ b/src/modules/SdnDiag.LoadBalancerMux/private/Get-SlbMuxConfigState.ps1 @@ -16,7 +16,7 @@ function Get-SlbMuxConfigState { $currentErrorActionPreference = $ErrorActionPreference $ProgressPreference = 'SilentlyContinue' - $ErrorActionPreference = 'SilentlyContinue' + $ErrorActionPreference = 'Ignore' try { $config = Get-SdnModuleConfiguration -Role 'LoadBalancerMux' diff --git a/src/modules/SdnDiag.LoadBalancerMux/public/Start-SdnMuxCertificateRotation.ps1 b/src/modules/SdnDiag.LoadBalancerMux/public/Start-SdnMuxCertificateRotation.ps1 index 754d3a56..5f4f285d 100644 --- a/src/modules/SdnDiag.LoadBalancerMux/public/Start-SdnMuxCertificateRotation.ps1 +++ b/src/modules/SdnDiag.LoadBalancerMux/public/Start-SdnMuxCertificateRotation.ps1 @@ -146,9 +146,12 @@ function Start-SdnMuxCertificateRotation { } -ArgumentList $obj.Certificate if ($certsToExamine) { + "`nMultiple certificates detected for Subject: {0}. Examine the certificates and cleanup if no longer needed." -f $obj.Certificate.Subject | Trace-Output -Level:Warning foreach ($cert in $certsToExamine) { - "Examine certificate subject {0} and thumbprint {1} on {2} and remove if no longer needed" -f $cert.Subject, $cert.Thumbprint, $obj.managementAddress | Trace-Output -Level:Warning + "`t[{0}] Thumbprint: {1}" -f $cert.PSComputerName, $cert.Thumbprint | Trace-Output -Level:Warning } + + Write-Host "" # insert empty line for better readability } # restart the slb mux service on the mux diff --git a/src/modules/SdnDiag.NetworkController/private/Get-NetworkControllerNodeInfoFromClusterManifest.ps1 b/src/modules/SdnDiag.NetworkController/private/Get-NetworkControllerNodeInfoFromClusterManifest.ps1 index c3d2fe85..96792d87 100644 --- a/src/modules/SdnDiag.NetworkController/private/Get-NetworkControllerNodeInfoFromClusterManifest.ps1 +++ b/src/modules/SdnDiag.NetworkController/private/Get-NetworkControllerNodeInfoFromClusterManifest.ps1 @@ -3,6 +3,12 @@ function Get-NetworkControllerNodeInfoFromClusterManifest { <# .SYNOPSIS This function is used as fallback method in the event that normal Get-NetworkControllerNode cmdlet fails in scenarios where certs may be expired + .PARAMETER NetworkController + Specifies the Network Controller to retrieve the information from. + .PARAMETER Name + Specifies the friendly name of the node for the network controller. If not provided, settings are retrieved for all nodes in the deployment. + .PARAMETER Credential + Specifies a user account that has permission to perform this action. The default is the current user. #> [CmdletBinding()] @@ -10,6 +16,9 @@ function Get-NetworkControllerNodeInfoFromClusterManifest { [Parameter(Mandatory = $false)] [String]$NetworkController = $(HostName), + [Parameter(Mandatory = $false)] + [String]$Name, + [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] @@ -36,5 +45,9 @@ function Get-NetworkControllerNodeInfoFromClusterManifest { $array += $object } + if ($Name) { + return ($array | Where-Object { $_.Name.Split(".")[0] -ieq $Name.Split(".")[0] -or $_.Server -ieq $Name.Split(".")[0] }) + } + return $array } diff --git a/src/modules/SdnDiag.NetworkController/private/Get-SdnNetworkControllerInfoFromClusterManifest.ps1 b/src/modules/SdnDiag.NetworkController/private/Get-SdnNetworkControllerInfoFromClusterManifest.ps1 index ddb4f31d..e48772ad 100644 --- a/src/modules/SdnDiag.NetworkController/private/Get-SdnNetworkControllerInfoFromClusterManifest.ps1 +++ b/src/modules/SdnDiag.NetworkController/private/Get-SdnNetworkControllerInfoFromClusterManifest.ps1 @@ -4,6 +4,8 @@ function Get-SdnNetworkControllerInfoFromClusterManifest { Get the Network Controller Configuration from network controller cluster manifest file. The function is used to retrieve information of the network controller when cluster down. .PARAMETER NetworkController Specifies the name the network controller node on which this cmdlet operates. The parameter is optional if running on network controller node. + .PARAMETER Name + Specifies the friendly name of the node for the network controller. If not provided, settings are retrieved for all nodes in the deployment. .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. #> @@ -13,43 +15,38 @@ function Get-SdnNetworkControllerInfoFromClusterManifest { [Parameter(Mandatory = $false)] [String]$NetworkController = $(HostName), + [Parameter(Mandatory = $false)] + [String]$Name, + [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty ) - "Attempting to retrieve NetworkController information via ClusterManifest" | Trace-Output + "Attempting to retrieve NetworkControllerNode information via ClusterManifest" | Trace-Output + $array = @() - $clusterManifestXml = [xml](Get-SdnServiceFabricClusterManifest -NetworkController $NetworkController -Credential $Credential) - $nodeList = $clusterManifestXml.ClusterManifest.Infrastructure.WindowsServer.NodeList.Node.NodeName - $secretCertThumbprint = $clusterManifestXml.ClusterManifest.Certificates.SecretsCertificate.X509FindValue + $clusterManifest = [xml](Get-SdnServiceFabricClusterManifest -NetworkController $NetworkController -Credential $Credential) + $clusterManifest.ClusterManifest.Infrastructure.WindowsServer.NodeList.Node | ForEach-Object { + $object = [PSCustomObject]@{ + Name = $_.NodeName + Server = $_.IPAddressOrFQDN + FaultDomain = $_.FaultDomain + RestInterface = $null + Status = $null + NodeCertificate = $null + } - $splat = @{ - Path = 'Cert:\LocalMachine\My' - Thumbprint = $secretCertThumbprint - } + $certificate = ($clusterManifest.ClusterManifest.NodeTypes.NodeType | Where-Object Name -ieq $_.NodeName).Certificates.ServerCertificate.X509FindValue.ToString() + $object | Add-Member -MemberType NoteProperty -Name NodeCertificateThumbprint -Value $certificate - if (Test-ComputerNameIsLocal -ComputerName $NetworkController) { - $serverCertificate = Get-SdnCertificate @splat - } - else { - $serverCertificate = Invoke-PSRemoteCommand -ComputerName $NetworkController -Credential $Credential -ScriptBlock { - param([Parameter(Position = 0)][String]$param1, [Parameter(Position = 1)][String]$param2) - Get-SdnCertificate -Path $param1 -Thumbprint $param2 - } -ArgumentList @($splat.Path, $splat.Thumbprint) + $array += $object } - $infraInfo = [PSCustomObject]@{ - Node = $nodeList - ClientAuthentication = $null - ClientCertificateThumbprint = $null - ClientSecurityGroup = $null - ServerCertificate = $serverCertificate - RestIPAddress = $null - RestName = $null - Version = $null + if ($Name) { + return ($array | Where-Object { $_.Name.Split(".")[0] -ieq $Name.Split(".")[0] -or $_.Server -ieq $Name.Split(".")[0] }) } - return $infraInfo + return $array } diff --git a/src/modules/SdnDiag.NetworkController/private/Invoke-CertRotateCommand.ps1 b/src/modules/SdnDiag.NetworkController/private/Invoke-CertRotateCommand.ps1 index 640d8953..fb7abe19 100644 --- a/src/modules/SdnDiag.NetworkController/private/Invoke-CertRotateCommand.ps1 +++ b/src/modules/SdnDiag.NetworkController/private/Invoke-CertRotateCommand.ps1 @@ -6,6 +6,9 @@ function Invoke-CertRotateCommand { [ValidateSet('Set-NetworkController', 'Set-NetworkControllerCluster', 'Set-NetworkControllerNode')] [System.String]$Command, + [Parameter(Mandatory = $false)] + [System.String]$Name, + [Parameter(Mandatory = $false)] [System.String]$NetworkController = $env:COMPUTERNAME, @@ -60,7 +63,7 @@ function Invoke-CertRotateCommand { $params.Add('CredentialEncryptionCertificate', $cert) } 'Set-NetworkControllerNode' { - $ncNode = Get-SdnNetworkControllerNode -Name $NetworkController -Credential $Credential + $ncNode = Get-SdnNetworkControllerNode -NetworkController $NetworkController -Name $Name -Credential $Credential $params.Add('Name', $ncNode.Name) $params.Add('NodeCertificate', $cert) diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnInfrastructureInfo.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnInfrastructureInfo.ps1 index 4ad1e08e..3786d25d 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnInfrastructureInfo.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnInfrastructureInfo.ps1 @@ -21,7 +21,7 @@ function Get-SdnInfrastructureInfo { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] - [String]$NetworkController = $(HostName), + [String]$NetworkController = $env:COMPUTERNAME, [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] @@ -46,13 +46,8 @@ function Get-SdnInfrastructureInfo { [Switch]$Force ) - if (-NOT ($PSBoundParameters.ContainsKey('NetworkController'))) { - $config = Get-SdnModuleConfiguration -Role 'NetworkController' - $confirmFeatures = Confirm-RequiredFeaturesInstalled -Name $config.windowsFeature - if (-NOT ($confirmFeatures)) { - "The current machine is not a NetworkController, run this on NetworkController or use -NetworkController parameter to specify one" | Trace-Output -Level:Warning - return # don't throw exception, since this is a controlled scenario and we do not need stack exception tracing - } + if (Test-ComputerNameIsLocal -ComputerName $NetworkController) { + Confirm-IsNetworkController } try { diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkController.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkController.ps1 index 43508ba9..834cafcf 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkController.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkController.ps1 @@ -15,7 +15,7 @@ function Get-SdnNetworkController { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] - [System.String]$NetworkController = $(HostName), + [System.String]$NetworkController = $env:COMPUTERNAME, [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] @@ -23,31 +23,18 @@ function Get-SdnNetworkController { $Credential = [System.Management.Automation.PSCredential]::Empty ) - if (-NOT ($PSBoundParameters.ContainsKey('NetworkController'))) { - $config = Get-SdnModuleConfiguration -Role 'NetworkController' - $confirmFeatures = Confirm-RequiredFeaturesInstalled -Name $config.windowsFeature - if (-NOT ($confirmFeatures)) { - "The current machine is not a NetworkController, run this on NetworkController or use -NetworkController parameter to specify one" | Trace-Output -Level:Warning - return # don't throw exception, since this is a controlled scenario and we do not need stack exception tracing - } - } - - $sb = { - # check if service fabric service is running otherwise this command will hang - if ((Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { - throw "Service Fabric Service is not running on $NetworkController" - } - - return (Get-NetworkController) + $networkControllerSB = { + Get-NetworkController } try { try { if (Test-ComputerNameIsLocal -ComputerName $NetworkController) { - $result = Invoke-Command -ScriptBlock $sb -ErrorAction Stop + Confirm-IsNetworkController + $result = Invoke-Command -ScriptBlock $networkControllerSB } else { - $result = Invoke-PSRemoteCommand -ComputerName $NetworkController -ScriptBlock $sb -Credential $Credential -ErrorAction Stop + $result = Invoke-PSRemoteCommand -ComputerName $NetworkController -ScriptBlock $networkControllerSB -Credential $Credential } } catch { diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerClusterInfo.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerClusterInfo.ps1 index f0c16af7..b4ef920f 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerClusterInfo.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerClusterInfo.ps1 @@ -69,8 +69,8 @@ function Get-SdnNetworkControllerClusterInfo { | Export-ObjectToFile -FilePath $outputDir.FullName -Name "Get-SdnServiceFabricReplica_$($service.ServiceTypeName)" -FileType txt } - Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -Credential $Credential -ScriptBlock {Get-ServiceFabricApplication} ` - | Export-ObjectToFile -FilePath $outputDir.FullName -Name "Get-ServiceFabricApplication" -FileType json + Get-SdnServiceFabricApplication -NetworkController $NetworkController -Credential $Credential ` + | Export-ObjectToFile -FilePath $outputDir.FullName -Name "Get-SdnServiceFabricApplication" -FileType json Get-SdnServiceFabricNode -NetworkController $NetworkController -Credential $Credential ` | Export-ObjectToFile -FilePath $outputDir.FullName -Name "Get-SdnServiceFabricNode" -FileType txt diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerNode.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerNode.ps1 index 163398c9..2d7c6d33 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerNode.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerNode.ps1 @@ -31,43 +31,38 @@ function Get-SdnNetworkControllerNode { [switch]$ServerNameOnly ) - if (-NOT ($PSBoundParameters.ContainsKey('NetworkController'))) { - $config = Get-SdnModuleConfiguration -Role 'NetworkController' - $confirmFeatures = Confirm-RequiredFeaturesInstalled -Name $config.windowsFeature - if (-NOT ($confirmFeatures)) { - "The current machine is not a NetworkController, run this on NetworkController or use -NetworkController parameter to specify one" | Trace-Output -Level:Warning - return # don't throw exception, since this is a controlled scenario and we do not need stack exception tracing - } - } - $params = @{ NetworkController = $NetworkController - Credential = $Credential - ErrorAction = 'Stop' + Credential = $Credential } if ($Name) { $params.Add('Name', $Name) } $sb = { - param([String]$arg0) - + param([String]$param1) # check if service fabric service is running otherwise this command will hang if ((Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { - throw "Service Fabric Service is not running on $NetworkController" + throw "FabricHostSvc is not running." } - if ([string]::IsNullOrEmpty($arg0)) { - Get-NetworkControllerNode -ErrorAction Stop + # native cmdlet to get network controller node information is case sensitive + # so we need to get all nodes and then filter based on the name + $ncNodes = Get-NetworkControllerNode + if (![string]::IsNullOrEmpty($param1)) { + return ($ncNodes | Where-Object {$_.Name -ieq $param1}) } else { - Get-NetworkControllerNode -Name $arg0 -ErrorAction Stop + return $ncNodes } } + if (Test-ComputerNameIsLocal -ComputerName $NetworkController) { + Confirm-IsNetworkController + } + try { try { - # Run the script block locally or remotely if (Test-ComputerNameIsLocal -ComputerName $NetworkController) { $result = Invoke-Command -ScriptBlock $sb -ArgumentList @($Name) -ErrorAction Stop } diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerNodeCertificate.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerNodeCertificate.ps1 index 2719f39b..6fd9cef7 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerNodeCertificate.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerNodeCertificate.ps1 @@ -2,18 +2,22 @@ function Get-SdnNetworkControllerNodeCertificate { <# .SYNOPSIS Returns the current Network Controller node certificate - .PARAMETER NetworkControllerOid - Specifies to return only the certificate that has the specified Network Controller OID. + .PARAMETER Credential + Specifies a user account that has permission to perform this action. The default is the current user. #> [CmdletBinding()] - param ( + param( [Parameter(Mandatory = $false)] - [switch]$NetworkControllerOid + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty ) + Confirm-IsNetworkController + try { - $networkControllerNode = Get-SdnNetworkControllerNode -Name $env:COMPUTERNAME + $networkControllerNode = Get-SdnNetworkControllerNode -Name $env:ComputerName -Credential $Credential # check to see if FindCertificateBy property exists as this was added in later builds # else if does not exist, default to Thumbprint for certificate diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerRestCertificate.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerRestCertificate.ps1 index 1c5dfe7d..3af583b5 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerRestCertificate.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnNetworkControllerRestCertificate.ps1 @@ -2,12 +2,22 @@ function Get-SdnNetworkControllerRestCertificate { <# .SYNOPSIS Returns the current Network Controller REST Certificate + .PARAMETER Credential + Specifies a user account that has permission to perform this action. The default is the current user. #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty + ) + Confirm-IsNetworkController try { - $networkController = Get-SdnNetworkController -ErrorAction 'Stop' + $networkController = Get-SdnNetworkController -NetworkController $env:COMPUTERNAME -Credential $Credential $ncRestCertThumprint = $($networkController.ServerCertificate.Thumbprint).ToString() $certificate = Get-SdnCertificate -Path 'Cert:\LocalMachine\My' -Thumbprint $ncRestCertThumprint -ErrorAction 'Stop' } diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricApplication.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricApplication.ps1 new file mode 100644 index 00000000..e86a48b6 --- /dev/null +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricApplication.ps1 @@ -0,0 +1,46 @@ +function Get-SdnServiceFabricApplication { + <# + .SYNOPSIS + Gets the health of a Service Fabric application from Network Controller. + .PARAMETER NetworkController + Specifies the name of the network controller node on which this cmdlet operates. + .PARAMETER ApplicationName + A service fabric application name that exists on the provided ring, such as fabric:/NetworkController. + .PARAMETER Credential + Specifies a user account that has permission to perform this action. The default is the current user. + .EXAMPLE + PS> Get-SdnServiceFabricApplication -NetworkController 'NC01' -Credential (Get-Credential) + #> + + [CmdletBinding()] + param ( + [Parameter(Mandatory = $false)] + [System.String]$NetworkController = $env:COMPUTERNAME, + + [Parameter(Mandatory = $false, ValueFromPipeline = $false)] + [String]$ApplicationName = 'fabric:/NetworkController', + + [Parameter(Mandatory = $false)] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()] + $Credential = [System.Management.Automation.PSCredential]::Empty + ) + + $sb = { + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." + } + + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricApplication + } + + try { + Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -Credential $Credential -ScriptBlock $sb -ArgumentList @($ApplicationName) + } + catch { + $_ | Trace-Exception + $_ | Write-Error + } +} diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricApplicationHealth.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricApplicationHealth.ps1 index 734915a5..a457c34e 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricApplicationHealth.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricApplicationHealth.ps1 @@ -15,7 +15,7 @@ function Get-SdnServiceFabricApplicationHealth { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] - [System.String[]]$NetworkController = $global:SdnDiagnostics.EnvironmentInfo.NetworkController, + [System.String]$NetworkController = $env:COMPUTERNAME, [Parameter(Mandatory = $false, ValueFromPipeline = $false)] [String]$ApplicationName = 'fabric:/NetworkController', @@ -26,13 +26,19 @@ function Get-SdnServiceFabricApplicationHealth { $Credential = [System.Management.Automation.PSCredential]::Empty ) - try { - if ($NetworkController) { - Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -ScriptBlock { Get-ServiceFabricApplicationHealth -ApplicationName $using:ApplicationName } -Credential $Credential - } - else { - Invoke-SdnServiceFabricCommand -ScriptBlock { Get-ServiceFabricApplicationHealth -ApplicationName $using:ApplicationName } -Credential $Credential + $sb = { + param([string]$param1) + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." } + + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricApplicationHealth -ApplicationName $param1 + } + + try { + Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -Credential $Credential -ScriptBlock $sb -ArgumentList @($ApplicationName) } catch { $_ | Trace-Exception diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterConfig.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterConfig.ps1 index 21ca19cc..93994140 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterConfig.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterConfig.ps1 @@ -2,77 +2,70 @@ function Get-SdnServiceFabricClusterConfig { <# .SYNOPSIS Gets Service Fabric Cluster Config Properties. - .PARAMETER NetworkController - Specifies the name of the network controller node on which this cmdlet operates. Default to local machine. .PARAMETER Uri The Uri to read properties from ClusterConfiguration, GlobalConfiguration .PARAMETER Name Property Name to filter the result. If not specified, it will return all properties. - .PARAMETER Credential - Specifies a user account that has permission to perform this action. The default is the current user. .EXAMPLE - PS> Get-SdnServiceFabricClusterConfig -NetworkController 'NC01' -Uri "ClusterConfiguration" -Credential (Get-Credential) + PS> Get-SdnServiceFabricClusterConfig -Uri "ClusterConfiguration" #> [CmdletBinding()] param ( - [Parameter(Mandatory = $false)] - [String]$NetworkController = $(HostName), - [Parameter(Mandatory = $true)] [ValidateSet('GlobalConfiguration', 'ClusterConfiguration')] [String]$Uri, [Parameter(Mandatory = $false)] - [String]$Name, - - [Parameter(Mandatory = $false)] - [System.Management.Automation.PSCredential] - [System.Management.Automation.Credential()] - $Credential = [System.Management.Automation.PSCredential]::Empty + [String]$Name ) + Confirm-IsNetworkController + $results = [System.Collections.ArrayList]::new() + try { Connect-ServiceFabricCluster | Out-Null + $client = [System.Fabric.FabricClient]::new() $result = $null $absoluteUri = "fabric:/NetworkController/$Uri" $binaryMethod = [System.Fabric.NamedProperty].getmethod("GetValue").MakeGenericMethod([byte[]]) $stringMethod = [System.Fabric.NamedProperty].getmethod("GetValue").MakeGenericMethod([string]) - $results = [System.Collections.ArrayList]::new() do { $result = $client.PropertyManager.EnumeratePropertiesAsync($absoluteUri, $true, $result).Result $result.GetEnumerator() | ForEach-Object { - $propertyName = $_.Metadata.PropertyName - $propertyObj = [PSCustomObject]@{ - Name = $propertyName + Name = $_.Metadata.PropertyName Value = $null } - if($_.Metadata.TypeId -ieq "string"){ + + if ($_.Metadata.TypeId -ieq "string") { $value = $stringMethod.Invoke($_, $null); $propertyObj.Value = $value - }elseif($_.Metadata.TypeId -ieq "binary"){ + } + elseif ($_.Metadata.TypeId -ieq "binary") { # only binary value exist is certificate $value = $binaryMethod.Invoke($_, $null); $certObj = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($value) $propertyObj.Value = $certObj } - if($PSBoundParameters.ContainsKey('Name')){ - if($propertyName -ieq $Name){ - $results.Add($propertyObj) | Out-Null - # Property Name is uniqueue so when name found, return the list + if ($PSBoundParameters.ContainsKey('Name')) { + # PropertyName is unique so when name found, return the list + if ($_.Metadata.PropertyName -ieq $Name) { + [void]$results.Add($propertyObj) return $results } - }else{ - $results.Add($propertyObj) | Out-Null + } + else { + [void]$results.Add($propertyObj) } } } while ($result.HasMoreData) + return $results } catch { diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterHealth.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterHealth.ps1 index 0cfcf4d9..d7444d81 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterHealth.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterHealth.ps1 @@ -13,7 +13,7 @@ function Get-SdnServiceFabricClusterHealth { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] - [System.String[]]$NetworkController = $global:SdnDiagnostics.EnvironmentInfo.NetworkController, + [System.String]$NetworkController = $env:COMPUTERNAME, [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] @@ -21,13 +21,18 @@ function Get-SdnServiceFabricClusterHealth { $Credential = [System.Management.Automation.PSCredential]::Empty ) - try { - if ($NetworkController) { - Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -ScriptBlock { Get-ServiceFabricClusterHealth } -Credential $Credential - } - else { - Invoke-SdnServiceFabricCommand -ScriptBlock { Get-ServiceFabricClusterHealth } -Credential $Credential + $sb = { + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." } + + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricClusterHealth + } + + try { + Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -Credential $Credential -ScriptBlock $sb } catch { $_ | Trace-Exception diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterManifest.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterManifest.ps1 index 9092eec2..0e19dfa9 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterManifest.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricClusterManifest.ps1 @@ -15,7 +15,7 @@ function Get-SdnServiceFabricClusterManifest { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] - [System.String[]]$NetworkController = $env:COMPUTERNAME, + [System.String]$NetworkController = $env:COMPUTERNAME, [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] @@ -23,20 +23,21 @@ function Get-SdnServiceFabricClusterManifest { $Credential = [System.Management.Automation.PSCredential]::Empty ) - try { - if (-NOT ($PSBoundParameters.ContainsKey('NetworkController'))) { - $config = Get-SdnModuleConfiguration -Role 'NetworkController' - $confirmFeatures = Confirm-RequiredFeaturesInstalled -Name $config.windowsFeature - if (-NOT ($confirmFeatures)) { - "The current machine is not a NetworkController, run this on NetworkController or use -NetworkController parameter to specify one" | Trace-Output -Level:Warning - return # don't throw exception, since this is a controlled scenario and we do not need stack exception tracing - } + $sb = { + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." } + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricClusterManifest + } + + try { # in instances where Service Fabric is down/offline we want to catch any exceptions returned by Invoke-SdnServiceFabricCommand # and then fallback to getting the cluster manifest information from the file system directly try { - $clusterManifest = Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -ScriptBlock { Get-ServiceFabricClusterManifest } -Credential $Credential + $clusterManifest = Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -ScriptBlock $sb -Credential $Credential } catch { "Unable to retrieve ClusterManifest directly from Service Fabric. Attempting to retrieve ClusterManifest from file system" | Trace-Output -Level:Warning diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricNode.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricNode.ps1 index d2eff49d..893c2c54 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricNode.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricNode.ps1 @@ -19,7 +19,7 @@ function Get-SdnServiceFabricNode { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] - [System.String[]]$NetworkController = $env:COMPUTERNAME, + [System.String]$NetworkController = $env:COMPUTERNAME, [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] @@ -31,29 +31,33 @@ function Get-SdnServiceFabricNode { ) - try { + $sfParams = @{ + NetworkController = $NetworkController + Credential = $Credential + } + if ($NodeName) { + $sfParams.Add('ArgumentList', @($NodeName)) + } - if (-NOT ($PSBoundParameters.ContainsKey('NetworkController'))) { - $config = Get-SdnModuleConfiguration -Role 'NetworkController' - $confirmFeatures = Confirm-RequiredFeaturesInstalled -Name $config.windowsFeature - if (-NOT ($confirmFeatures)) { - "The current machine is not a NetworkController, run this on NetworkController or use -NetworkController parameter to specify one" | Trace-Output -Level:Warning - return # don't throw exception, since this is a controlled scenario and we do not need stack exception tracing - } + $sb = { + param([string]$param1) + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." } - if ($NodeName) { - $sb = { - Get-ServiceFabricNode -NodeName $using:NodeName - } + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + + if ($param1) { + Get-ServiceFabricNode -NodeName $param1 } else { - $sb = { - Get-ServiceFabricNode - } + Get-ServiceFabricNode } + } - Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -ScriptBlock $sb -Credential $Credential + try { + Invoke-SdnServiceFabricCommand @sfParams -ScriptBlock $sb } catch { $_ | Trace-Exception diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricPartition.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricPartition.ps1 index 63144436..54d865c8 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricPartition.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricPartition.ps1 @@ -38,7 +38,7 @@ function Get-SdnServiceFabricPartition { [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedService')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedServiceTypeName')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'PartitionID')] - [System.String[]]$NetworkController = $global:SdnDiagnostics.EnvironmentInfo.NetworkController, + [System.String]$NetworkController = $env:COMPUTERNAME, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedService')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedServiceTypeName')] @@ -48,37 +48,57 @@ function Get-SdnServiceFabricPartition { $Credential = [System.Management.Automation.PSCredential]::Empty ) - try { - switch ($PSCmdlet.ParameterSetName) { - 'NamedService' { - $sb = { - Get-ServiceFabricApplication -ApplicationName $using:ApplicationName | Get-ServiceFabricService -ServiceName $using:ServiceName | Get-ServiceFabricPartition + $sfParams = @{ + Credential = $Credential + NetworkController = $NetworkController + } + + switch ($PSCmdlet.ParameterSetName) { + 'NamedService' { + $sfParams.Add('ArgumentList',@($ApplicationName, $ServiceName)) + $sb = { + param([string]$param1, [string]$param2) + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." } + + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricApplication -ApplicationName $param1 | Get-ServiceFabricService -ServiceName $param2 | Get-ServiceFabricPartition } + } - 'NamedServiceTypeName' { - $sb = { - Get-ServiceFabricApplication -ApplicationName $using:ApplicationName | Get-ServiceFabricService -ServiceTypeName $using:ServiceTypeName | Get-ServiceFabricPartition + 'NamedServiceTypeName' { + $sfParams.Add('ArgumentList',@($ApplicationName, $ServiceTypeName)) + $sb = { + param([string]$param1, [string]$param2) + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." } + + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricApplication -ApplicationName $param1 | Get-ServiceFabricService -ServiceTypeName $param2 | Get-ServiceFabricPartition } + } - 'PartitionID' { - $sb = { - Get-ServiceFabricPartition -PartitionId $using:PartitionId + 'PartitionID' { + $sfParams.Add('ArgumentList',@($PartitionId)) + $sb = { + param([Guid]$param1) + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." } - } - default { - # no default + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricPartition -PartitionId $param1 } } + } - if ($NetworkController) { - return (Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -ScriptBlock $sb -Credential $Credential) - } - else { - return (Invoke-SdnServiceFabricCommand -ScriptBlock $sb -Credential $Credential) - } + try { + Invoke-SdnServiceFabricCommand @sfParams -ScriptBlock $sb } catch { $_ | Trace-Exception diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricReplica.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricReplica.ps1 index f555c80a..523e00b0 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricReplica.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricReplica.ps1 @@ -32,7 +32,7 @@ function Get-SdnServiceFabricReplica { [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedService')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedServiceTypeName')] - [System.String[]]$NetworkController = $global:SdnDiagnostics.EnvironmentInfo.NetworkController, + [System.String]$NetworkController = $env:COMPUTERNAME, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedService')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedServiceTypeName')] @@ -45,31 +45,43 @@ function Get-SdnServiceFabricReplica { [Switch]$Primary ) - try { - switch ($PSCmdlet.ParameterSetName) { - 'NamedService' { - $sb = { - Get-ServiceFabricApplication -ApplicationName $using:ApplicationName | Get-ServiceFabricService -ServiceName $using:ServiceName | Get-ServiceFabricPartition | Get-ServiceFabricReplica + $sfParams = @{ + NetworkController = $NetworkController + Credential = $Credential + } + + switch ($PSCmdlet.ParameterSetName) { + 'NamedService' { + $sfParams.Add('ArgumentList', @($ApplicationName, $ServiceName)) + $sb = { + param([string]$param1, [string]$param2) + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." } + + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricApplication -ApplicationName $param1 | Get-ServiceFabricService -ServiceName $param2 | Get-ServiceFabricPartition | Get-ServiceFabricReplica } + } - 'NamedServiceTypeName' { - $sb = { - Get-ServiceFabricApplication -ApplicationName $using:ApplicationName | Get-ServiceFabricService -ServiceTypeName $using:ServiceTypeName | Get-ServiceFabricPartition | Get-ServiceFabricReplica + 'NamedServiceTypeName' { + $sfParams.Add('ArgumentList', @($ApplicationName, $ServiceTypeName)) + $sb = { + param([string]$param1, [string]$param2) + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." } - } - default { - # no default + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricApplication -ApplicationName $param1 | Get-ServiceFabricService -ServiceTypeName $param2 | Get-ServiceFabricPartition | Get-ServiceFabricReplica } } + } - if ($NetworkController) { - $replica = Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -ScriptBlock $sb -Credential $Credential - } - else { - $replica = Invoke-SdnServiceFabricCommand -ScriptBlock $sb -Credential $Credential - } + try { + $replica = Invoke-SdnServiceFabricCommand @sfParams -ScriptBlock $sb # as network controller only leverages stateful service fabric services, we will have Primary and ActiveSecondary replicas # if the -Primary switch was declared, we only want to return the primary replica for that particular service diff --git a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricService.ps1 b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricService.ps1 index 5d96caa5..e2eb9cc5 100644 --- a/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricService.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Get-SdnServiceFabricService.ps1 @@ -18,71 +18,82 @@ function Get-SdnServiceFabricService { PS> Get-SdnServiceFabricService -NetworkController 'Prefix-NC01' -Credential (Get-Credential) -ServiceTypeName 'ApiService' #> - [CmdletBinding(DefaultParameterSetName = 'NamedService')] + [CmdletBinding(DefaultParameterSetName = 'Default')] param( - [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedService')] - [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedServiceTypeName')] + [Parameter(Mandatory = $false, ParameterSetName = 'Default')] + [Parameter(Mandatory = $false, ParameterSetName = 'NamedService')] + [Parameter(Mandatory = $false, ParameterSetName = 'NamedServiceTypeName')] [System.String]$ApplicationName = 'fabric:/NetworkController', - [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedService')] + [Parameter(Mandatory = $true, ParameterSetName = 'NamedService')] [System.String]$ServiceName, - [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedServiceTypeName')] + [Parameter(Mandatory = $true, ParameterSetName = 'NamedServiceTypeName')] [System.String]$ServiceTypeName, - [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedService')] - [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedServiceTypeName')] - [System.String[]]$NetworkController = $global:SdnDiagnostics.EnvironmentInfo.NetworkController, + [Parameter(Mandatory = $false, ParameterSetName = 'Default')] + [Parameter(Mandatory = $false, ParameterSetName = 'NamedService')] + [Parameter(Mandatory = $false, ParameterSetName = 'NamedServiceTypeName')] + [System.String]$NetworkController = $env:COMPUTERNAME, - [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedService')] - [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedServiceTypeName')] + [Parameter(Mandatory = $false, ParameterSetName = 'Default')] + [Parameter(Mandatory = $false, ParameterSetName = 'NamedService')] + [Parameter(Mandatory = $false, ParameterSetName = 'NamedServiceTypeName')] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty ) - try { - switch ($PSCmdlet.ParameterSetName) { - 'NamedService' { - if ($ServiceName) { - $sb = { - Get-ServiceFabricApplication -ApplicationName $using:ApplicationName | Get-ServiceFabricService -ServiceName $using:ServiceName - } - } - else { - $sb = { - Get-ServiceFabricApplication -ApplicationName $using:ApplicationName | Get-ServiceFabricService - } - } - } + $sfParams = @{ + NetworkController = $NetworkController + Credential = $Credential + } - 'NamedServiceTypeName' { - if ($ServiceTypeName) { - $sb = { - Get-ServiceFabricApplication -ApplicationName $using:ApplicationName | Get-ServiceFabricService -ServiceTypeName $using:ServiceTypeName - } - } - else { - $sb = { - Get-ServiceFabricApplication -ApplicationName $using:ApplicationName | Get-ServiceFabricService - } + switch ($PSCmdlet.ParameterSetName) { + 'NamedService' { + $sfParams.Add('ArgumentList',@($ApplicationName, $ServiceName)) + $sb = { + param([string]$param1, [string]$param2) + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." } - } - default { - $sb = { - Get-ServiceFabricApplication | Get-ServiceFabricService - } + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricApplication -ApplicationName $param1 | Get-ServiceFabricService -ServiceName $param2 } } + 'NamedServiceTypeName' { + $sfParams.Add('ArgumentList',@($ApplicationName, $ServiceTypeName)) + $sb = { + param([string]$param1, [string]$param2) + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." + } - if ($NetworkController) { - Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -ScriptBlock $sb -Credential $Credential + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricApplication -ApplicationName $param1 | Get-ServiceFabricService -ServiceTypeName $param2 + } } - else { - Invoke-SdnServiceFabricCommand -ScriptBlock $sb -Credential $Credential + default { + $sfParams.Add('ArgumentList',@($ApplicationName)) + $sb = { + param([string]$param1) + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." + } + + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Get-ServiceFabricApplication -ApplicationName $param1 | Get-ServiceFabricService + } } } + + try { + Invoke-SdnServiceFabricCommand @sfParams -ScriptBlock $sb + } catch { $_ | Trace-Exception $_ | Write-Error diff --git a/src/modules/SdnDiag.NetworkController/public/Invoke-SdnServiceFabricCommand.ps1 b/src/modules/SdnDiag.NetworkController/public/Invoke-SdnServiceFabricCommand.ps1 index af20f0ed..e8dbbca8 100644 --- a/src/modules/SdnDiag.NetworkController/public/Invoke-SdnServiceFabricCommand.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Invoke-SdnServiceFabricCommand.ps1 @@ -17,7 +17,7 @@ function Invoke-SdnServiceFabricCommand { [CmdletBinding()] param( [Parameter(Mandatory = $false)] - [System.String[]]$NetworkController = $env:COMPUTERNAME, + [System.String]$NetworkController = $env:COMPUTERNAME, [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] @@ -37,81 +37,20 @@ function Invoke-SdnServiceFabricCommand { if ($ArgumentList) { $params.Add('ArgumentList', $ArgumentList) } - - if (-NOT ($PSBoundParameters.ContainsKey('NetworkController'))) { - $config = Get-SdnModuleConfiguration -Role 'NetworkController' - $confirmFeatures = Confirm-RequiredFeaturesInstalled -Name $config.windowsFeature - if (-NOT ($confirmFeatures)) { - "The current machine is not a NetworkController, run this on NetworkController or use -NetworkController parameter to specify one" | Trace-Output -Level:Warning - return # don't throw exception, since this is a controlled scenario and we do not need stack exception tracing - } + if (-NOT (Test-ComputerNameIsLocal -ComputerName $NetworkController)) { + $params.Add('ComputerName', $NetworkController) + $params.Add('Credential', $Credential) } - - foreach ($controller in $NetworkController) { - - $i = 0 - $maxRetry = 3 - - # due to scenario as described in https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-troubleshoot-local-cluster-setup#cluster-connection-fails-with-object-is-closed - # we want to catch any exception when connecting to service fabric cluster, and if necassary destroy and create a new remote pssession - "Invoke Service Fabric cmdlets against {0}" -f $controller | Trace-Output -Level Verbose - while ($i -lt $maxRetry) { - $i++ - - $session = New-PSRemotingSession -ComputerName $controller -Credential $Credential - if (!$session) { - "No session could be established to {0}" -f $controller | Trace-Output -Level:Error - break - } - - try { - $connection = Invoke-Command -Session $session -ScriptBlock { - # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket - Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null - } -ErrorAction Stop - } - catch { - "Unable to connect to Service Fabric Cluster. Attempt {0}/{1}`n`t{2}" -f $i, $maxRetry, $_ | Trace-Output -Level:Error - "Terminating remote session {0} to {1}" -f $session.Name, $session.ComputerName | Trace-Output -Level:Warning - Get-PSSession -Id $session.Id | Remove-PSSession - } - } - - # if we were not able to create a connection - # we want to continue the foreach statement to connect to another network controller node (if provided) - if (!$connection) { - "Unable to connect to Service Fabric Cluster" | Trace-Output -Level:Error - continue - } - - # if we have the session created, we can then construct the remainder of the parameters for splatting purposes - # and write some verbose details to the log for tracking purposes - if ($session) { - if (-NOT ($params.ContainsKey('Session'))) { - $params.Add('Session', $session) - } - else { - $params.Session = $session - } - - "NetworkController: {0}, ScriptBlock: {1}" -f $controller, $ScriptBlock.ToString() | Trace-Output -Level:Verbose - if ($params.ArgumentList) { - "ArgumentList: {0}" -f ($params.ArgumentList | ConvertTo-Json).ToString() | Trace-Output -Level:Verbose - } - - # if we get results from service fabric, then we want to break out of the loop - # otherwise we will try again to see if state issue with service fabric or the particular node - $sfResults = Invoke-Command @params - if ($sfResults) { - break - } - } + else { + Confirm-IsNetworkController } - if (!$sfResults) { - throw New-Object System.NullReferenceException("Unable to return results from service fabric") + "NetworkController: {0}, ScriptBlock: {1}" -f $NetworkController, $ScriptBlock.ToString() | Trace-Output -Level:Verbose + if ($params.ArgumentList) { + "ArgumentList: {0}" -f ($params.ArgumentList | ConvertTo-Json).ToString() | Trace-Output -Level:Verbose } + $sfResults = Invoke-Command @params -ErrorAction Stop if ($sfResults.GetType().IsPrimitive -or ($sfResults -is [String])) { return $sfResults } diff --git a/src/modules/SdnDiag.NetworkController/public/Move-SdnServiceFabricReplica.ps1 b/src/modules/SdnDiag.NetworkController/public/Move-SdnServiceFabricReplica.ps1 index 9bc7b339..87227498 100644 --- a/src/modules/SdnDiag.NetworkController/public/Move-SdnServiceFabricReplica.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Move-SdnServiceFabricReplica.ps1 @@ -32,7 +32,7 @@ function Move-SdnServiceFabricReplica { [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedService')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedServiceTypeName')] - [System.String[]]$NetworkController = $global:SdnDiagnostics.EnvironmentInfo.NetworkController, + [System.String]$NetworkController = $env:COMPUTERNAME, [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedService')] [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = 'NamedServiceTypeName')] @@ -44,25 +44,41 @@ function Move-SdnServiceFabricReplica { [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty ) - try { - if ($PSCmdlet.ParameterSetName -eq 'NamedService') { - $sfParams = @{ - ServiceName = $ServiceName - Credential = $Credential - } + + $sfParams = @{ + NetworkController = $NetworkController + Credential = $Credential + } + $moveSfParams = $sfParams.Clone() + + switch ($PSCmdlet.ParameterSetName) { + 'NamedService' { + $sfParams.Add('ServiceName', $ServiceName) + } + 'NamedServiceTypeName' { + $sfParams.Add('ServiceTypeName', $ServiceTypeName) + } + } + + $moveReplicaSB = { + param([string]$param1, [string]$param2) + $splat = @{ + ServiceName = $param1 } - elseif ($PSCmdlet.ParameterSetName -eq 'NamedServiceTypeName') { - $sfParams = @{ - ServiceTypeName = $ServiceTypeName - Credential = $Credential - } + if (-NOT [string]::IsNullOrEmpty($param2)) { + $splat.Add('NodeName', $param2) } - # add NetworkController to hash table for splatting if defined - if ($NetworkController) { - [void]$sfParams.Add('NetworkController', $NetworkController) + if (( Get-Service -Name 'FabricHostSvc').Status -ine 'Running' ) { + throw "Service Fabric Service is currently not running." } + # The 3>$null 4>$null sends unwanted verbose and debug streams into the bit bucket + $null = Connect-ServiceFabricCluster -TimeoutSec 15 3>$null 4>$null + Move-ServiceFabricPrimaryReplica @splat + } + + try { # check to determine how many replicas are part of the partition for the service # if we only have a single replica, then generate a warning and stop further processing # otherwise locate the primary replica @@ -74,27 +90,12 @@ function Move-SdnServiceFabricReplica { } $replicaBefore = $serviceFabricReplicas | Where-Object {$_.ReplicaRole -ieq 'Primary'} - - # regardless if user defined ServiceName or ServiceTypeName, the $service object returned will include the ServiceName property - # which we will use to perform the move operation with - if ($NodeName) { - $sb = { - Move-ServiceFabricPrimaryReplica -ServiceName $using:service.ServiceName -NodeName $using:NodeName - } - } - else { - $sb = { - Move-ServiceFabricPrimaryReplica -ServiceName $using:service.ServiceName - } - } + "Replica currently is on {0}" -f $replicaBefore.NodeName | Trace-Output -Level:Verbose # no useful information is returned during the move operation, so we will just null the results that are returned back - if ($NetworkController) { - $null = Invoke-SdnServiceFabricCommand -NetworkController $NetworkController -ScriptBlock $sb -Credential $Credential -ErrorAction Stop - } - else { - $null = Invoke-SdnServiceFabricCommand -ScriptBlock $sb -Credential $Credential -ErrorAction Stop - } + $moveSfParams.Add('ArgumentList', @($service.ServiceName, $NodeName)) + $moveSfParams.Add('ScriptBlock', $moveReplicaSB) + $null = Invoke-SdnServiceFabricCommand @moveSfParams # update the hash table to now define -Primary switch, which will be used to get the service fabric replica primary [void]$sfParams.Add('Primary', $true) diff --git a/src/modules/SdnDiag.NetworkController/public/Set-SdnNetworkController.ps1 b/src/modules/SdnDiag.NetworkController/public/Set-SdnNetworkController.ps1 index c48ecd68..916ea782 100644 --- a/src/modules/SdnDiag.NetworkController/public/Set-SdnNetworkController.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Set-SdnNetworkController.ps1 @@ -39,28 +39,14 @@ function Set-SdnNetworkController { $params.Add('Credential', $Credential) } - # we do not support this operation being executed from remote session - # unless we have explicitly specified the Credential parameter + Confirm-IsAdmin + Confirm-IsNetworkController if ($PSSenderInfo) { if ($Credential -eq [System.Management.Automation.PSCredential]::Empty -or $null -eq $Credential) { throw New-Object System.NotSupportedException("This operation is not supported in a remote session without supplying -Credential.") } } - # ensure that the module is running as local administrator - $elevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) - if (-NOT $elevated) { - throw New-Object System.Exception("This function requires elevated permissions. Run PowerShell as an Administrator and import the module again.") - } - - # add disclaimer that this feature is currently under preview - "This feature is currently under preview. Please report any issues to https://github.com/microsoft/SdnDiagnostics/issues." | Trace-Output -Level:Warning - $confirm = Confirm-UserInput -Message "Do you want to proceed with operation? [Y/N]:" - if (-NOT $confirm) { - "User has opted to abort the operation. Terminating operation" | Trace-Output -Level:Warning - return - } - try { $getNetworkController = Get-SdnNetworkController if ($null -eq $getNetworkController) { diff --git a/src/modules/SdnDiag.NetworkController/public/Start-SdnCertificateRotation.ps1 b/src/modules/SdnDiag.NetworkController/public/Start-SdnCertificateRotation.ps1 index c086efbd..a33d2eaf 100644 --- a/src/modules/SdnDiag.NetworkController/public/Start-SdnCertificateRotation.ps1 +++ b/src/modules/SdnDiag.NetworkController/public/Start-SdnCertificateRotation.ps1 @@ -141,12 +141,12 @@ function Start-SdnCertificateRotation { } # before we proceed with anything else, we want to make sure that all the Network Controllers within the SDN fabric are running the current version - Install-SdnDiagnostics -ComputerName $sdnFabricDetails.NetworkController -ErrorAction Stop + Install-SdnDiagnostics -ComputerName $sdnFabricDetails.NetworkController -Credential $Credential -ErrorAction Stop "Network Controller version: {0}" -f $ncSettings.NetworkControllerVersion | Trace-Output "Network Controller cluster version: {0}" -f $ncSettings.NetworkControllerClusterVersion | Trace-Output - $healthState = Get-SdnServiceFabricClusterHealth -NetworkController $env:COMPUTERNAME + $healthState = Get-SdnServiceFabricClusterHealth -NetworkController $env:COMPUTERNAME -Credential $Credential if ($healthState.AggregatedHealthState -ine 'Ok') { "Service Fabric AggregatedHealthState is currently reporting {0}. Please address underlying health before proceeding with certificate rotation" ` -f $healthState.AggregatedHealthState | Trace-Output -Level:Error diff --git a/src/modules/SdnDiag.Server/SdnDiag.Server.Helper.psm1 b/src/modules/SdnDiag.Server/SdnDiag.Server.Helper.psm1 index c8a73f13..0e909b95 100644 --- a/src/modules/SdnDiag.Server/SdnDiag.Server.Helper.psm1 +++ b/src/modules/SdnDiag.Server/SdnDiag.Server.Helper.psm1 @@ -133,17 +133,14 @@ class VfpEncapRule : VfpRule { [string]$EncapType [string[]]$EncapDestination [string]$EncapSourceIP + [string]$Transposition + [string[]]$Modify [string[]]$RuleData [int]$GREKey } class VfpFirewallRule : VfpRule {} -class VfpVnetRule : VfpRule { - [string]$Transposition - [string[]]$Modify -} - class VfpPortState { [boolean]$Enabled [boolean]$Blocked diff --git a/src/modules/SdnDiag.Server/private/Get-ServerConfigState.ps1 b/src/modules/SdnDiag.Server/private/Get-ServerConfigState.ps1 index 3270dcef..615a4a83 100644 --- a/src/modules/SdnDiag.Server/private/Get-ServerConfigState.ps1 +++ b/src/modules/SdnDiag.Server/private/Get-ServerConfigState.ps1 @@ -16,7 +16,7 @@ function Get-ServerConfigState { $currentErrorActionPreference = $ErrorActionPreference $ProgressPreference = 'SilentlyContinue' - $ErrorActionPreference = 'SilentlyContinue' + $ErrorActionPreference = 'Ignore' try { $config = Get-SdnModuleConfiguration -Role:Server @@ -38,7 +38,6 @@ function Get-ServerConfigState { foreach ($vm in (Get-WmiObject -na root\virtualization\v2 msvm_computersystem)) { foreach ($vma in $vm.GetRelated("Msvm_SyntheticEthernetPort")) { foreach ($port in $vma.GetRelated("Msvm_SyntheticEthernetPortSettingData").GetRelated("Msvm_EthernetPortAllocationSettingData").GetRelated("Msvm_EthernetSwitchPort")) { - $outputDir = New-Item -Path (Join-Path -Path $OutputDirectory.FullName -ChildPath "VFP\$($vm.ElementName)") -ItemType Directory -Force vfpctrl /list-nat-range /port $($port.Name) | Export-ObjectToFile -FilePath $outputDir.FullName -Prefix 'vfpctrl_list_nat_range' -Name $port.Name -FileType txt vfpctrl /list-rule /port $($port.Name) | Export-ObjectToFile -FilePath $outputDir.FullName -Prefix 'vfpctrl_list_rule' -Name $port.Name -FileType txt @@ -69,20 +68,53 @@ function Get-ServerConfigState { Get-SdnOvsdbPhysicalPort | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-SdnOvsdbPhysicalPort' -FileType json Get-SdnOvsdbUcastMacRemoteTable | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-SdnOvsdbUcastMacRemoteTable' -FileType json + # Get virtual machine details + "Gathering virtual machine configuration details" | Trace-Output -Level:Verbose + $vm = Get-VM + if ($vm) { + $vmRootDir = New-Item -Path (Join-Path -Path $OutputDirectory.FullName -ChildPath "VM") -ItemType Directory -Force + + $vm | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VM' -FileType csv + $vm | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VM' -FileType json + $vm | ForEach-Object { + $prefix = $_.Name.ToString().Replace(" ", "_").Trim() + $_ | Get-VMNetworkAdapter | Export-ObjectToFile -FilePath $vmRootDir.FullName -Prefix $prefix -Name 'Get-VMNetworkAdapter' -FileType json + $_ | Get-VMNetworkAdapterAcl | Export-ObjectToFile -FilePath $vmRootDir.FullName -Prefix $prefix -Name 'Get-VMNetworkAdapterAcl' -FileType json + $_ | Get-VMNetworkAdapterExtendedAcl | Export-ObjectToFile -FilePath $vmRootDir.FullName -Prefix $prefix -Name 'Get-VMNetworkAdapterExtendedAcl' -FileType json + $_ | Get-VMNetworkAdapterIsolation | Export-ObjectToFile -FilePath $vmRootDir.FullName -Prefix $prefix -Name 'Get-VMNetworkAdapterIsolation' -FileType json + $_ | Get-VMNetworkAdapterRoutingDomainMapping | Export-ObjectToFile -FilePath $vmRootDir.FullName -Prefix $prefix -Name 'Get-VMNetworkAdapterRoutingDomainMapping' -FileType json + $_ | Get-VMNetworkAdapterTeamMapping | Export-ObjectToFile -FilePath $vmRootDir.FullName -Prefix $prefix -Name 'Get-VMNetworkAdapterTeamMapping' -FileType json + $_ | Get-VMNetworkAdapterVLAN | Export-ObjectToFile -FilePath $vmRootDir.FullName -Prefix $prefix -Name 'Get-VMNetworkAdapterVLAN' -FileType json + } + } + # Gather Hyper-V network details - "Gathering hyper-v configuration details" | Trace-Output -Level:Verbose - Get-VM | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VM' -FileType csv + "Gathering Hyper-V network configuration details" | Trace-Output -Level:Verbose Get-NetAdapterVPort | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-NetAdapterVPort' -FileType txt -Format Table Get-NetAdapterVmqQueue | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-NetAdapterVmqQueue' -FileType txt -Format Table Get-SdnNetAdapterEncapOverheadConfig | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-SdnNetAdapterEncapOverheadConfig' -FileType txt -Format Table - Get-VMSwitch | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VMSwitch' -FileType json - Get-VMSwitchTeam | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VMSwitchTeam' -FileType json Get-SdnVMNetworkAdapterPortProfile -AllVMs | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-SdnVMNetworkAdapterPortProfile' -FileType txt -Format Table Get-VMNetworkAdapterIsolation | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VMNetworkAdapterIsolation' -FileType txt -Format Table Get-VMNetworkAdapterVLAN | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VMNetworkAdapterVLAN' -FileType txt -Format Table Get-VMNetworkAdapterRoutingDomainMapping | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VMNetworkAdapterRoutingDomainMapping' -FileType txt -Format Table Get-VMSystemSwitchExtensionPortFeature -FeatureId "9940cd46-8b06-43bb-b9d5-93d50381fd56" | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VMSystemSwitchExtensionPortFeature' -FileType json + Get-VMSwitchTeam | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VMSwitchTeam' -FileType txt -Format List + $vmSwitch = Get-VMSwitch + if ($vmSwitch) { + $vmSwitchRootDir = New-Item -Path (Join-Path -Path $OutputDirectory.FullName -ChildPath "VMSwitch") -ItemType Directory -Force + + $vmSwitch | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VMSwitch' -FileType json + $vmSwitch | Export-ObjectToFile -FilePath $OutputDirectory.FullName -Name 'Get-VMSwitch' -FileType txt -Format List + $vmSwitch | ForEach-Object { + $prefix = $_.Name.ToString().Replace(" ", "_").Trim() + $_ | Get-VMSwitchExtension | Export-ObjectToFile -FilePath $vmSwitchRootDir.FullName -Prefix $prefix -Name 'Get-VMSwitchExtension' -FileType json + $_ | Get-VMSwitchExtensionSwitchData | Export-ObjectToFile -FilePath $vmSwitchRootDir.FullName -Prefix $prefix -Name 'Get-VMSwitchExtensionSwitchData' -FileType json + $_ | Get-VMSwitchExtensionSwitchFeature | Export-ObjectToFile -FilePath $vmSwitchRootDir.FullName -Prefix $prefix -Name 'Get-VMSwitchExtensionSwitchFeature' -FileType json + $_ | Get-VMSwitchTeam | Export-ObjectToFile -FilePath $vmSwitchRootDir.FullName -Prefix $prefix -Name 'Get-VMSwitchTeam' -FileType json + } + } + # add fault tolerance for hnvdiagnostics commands that do not have [CmdletBinding()] # and will ignore the ErrorActionPreference resulting in a terminating exception $hnvDiag = @( diff --git a/src/modules/SdnDiag.Server/private/Get-VfpPortRule.ps1 b/src/modules/SdnDiag.Server/private/Get-VfpPortRule.ps1 index c5792674..5eb54df6 100644 --- a/src/modules/SdnDiag.Server/private/Get-VfpPortRule.ps1 +++ b/src/modules/SdnDiag.Server/private/Get-VfpPortRule.ps1 @@ -44,8 +44,9 @@ function Get-VfpPortRule { # in situations where the value might be nested in another line we need to do some additional data processing # subkey is declared below if the value is null after the split if ($subKey) { + $doneProcessingSubKey = $false if($null -eq $subObject){ - $subObject = New-Object -TypeName PSObject + $subObject = [PSCustomObject]::new() } if ($null -eq $subArrayList) { $subArrayList = [System.Collections.ArrayList]::new() @@ -59,7 +60,8 @@ function Get-VfpPortRule { if ($line.Contains('Flow TTL')) { $object.Conditions = $subObject - $subObject = [PSCustomObject]::new() + $doneProcessingSubKey = $true + $subObject = $null $subKey = $null } @@ -67,7 +69,8 @@ function Get-VfpPortRule { elseif ($line.Contains('')) { $object.Conditions = $null - $subObject = [PSCustomObject]::new() + $doneProcessingSubKey = $true + $subObject = $null $subKey = $null } @@ -127,8 +130,13 @@ function Get-VfpPortRule { } } - # since we are processing sub values, we want to move to the next line and not do any further processing - continue + if ($doneProcessingSubKey) { + # we are done processing the subkey, so we can proceed to the rest of the script + } + else { + # we are not done processing the subkey values, so we need to continue to the next line + continue + } } # lines in the VFP output that contain : contain properties and values @@ -150,27 +158,57 @@ function Get-VfpPortRule { # create the custom object based on the layer # so that we can add appropriate properties - switch -Wildcard ($Layer) { - "*_METER_*" { - $object = [VfpMeterRule]@{ + switch ($Layer) { + "GW_PA_ROUTE_LAYER" { + $object = [VfpEncapRule]@{ Rule = $value } } - "FW_*" { + "FW_ADMIN_LAYER_ID" { $object = [VfpFirewallRule]@{ Rule = $value } } - "*_ENCAP_*" { + "FW_CONTROLLER_LAYER_ID" { + $object = [VfpFirewallRule]@{ + Rule = $value + } + } + + "VNET_METER_LAYER_OUT" { + $object = [VfpMeterRule]@{ + Rule = $value + } + } + + "VNET_MAC_REWRITE_LAYER" { $object = [VfpEncapRule]@{ Rule = $value } } - "VNET_*" { - $object = [VfpVnetRule]@{ + "VNET_ENCAP_LAYER" { + $object = [VfpEncapRule]@{ + Rule = $value + } + } + + "VNET_PA_ROUTE_LAYER" { + $object = [VfpEncapRule]@{ + Rule = $value + } + } + + "SLB_NAT_LAYER" { + $object = [VfpRule]@{ + Rule = $value + } + } + + "SLB_DECAP_LAYER_STATEFUL" { + $object = [VfpRule]@{ Rule = $value } } @@ -205,7 +243,8 @@ function Get-VfpPortRule { $object.$key = $value } catch { - "Unable to add {0} to object. Failing back to use NoteProperty." -f $key | Trace-Output -Level:Warning + # this is the fallback method to just add a property to the object + # outside of the defined class properties $object | Add-Member -MemberType NoteProperty -Name $key -Value $value continue } diff --git a/src/modules/SdnDiag.Server/public/Start-SdnServerCertificateRotation.ps1 b/src/modules/SdnDiag.Server/public/Start-SdnServerCertificateRotation.ps1 index b5e77afd..bbf1ac87 100644 --- a/src/modules/SdnDiag.Server/public/Start-SdnServerCertificateRotation.ps1 +++ b/src/modules/SdnDiag.Server/public/Start-SdnServerCertificateRotation.ps1 @@ -151,9 +151,12 @@ function Start-SdnServerCertificateRotation { } -ArgumentList $obj.Certificate if ($certsToExamine) { + "`nMultiple certificates detected for Subject: {0}. Examine the certificates and cleanup if no longer needed." -f $obj.Certificate.Subject | Trace-Output -Level:Warning foreach ($cert in $certsToExamine) { - "Examine certificate subject {0} and thumbprint {1} on {2} and remove if no longer needed" -f $cert.Subject, $cert.Thumbprint, $obj.managementAddress | Trace-Output -Level:Warning + "`t[{0}] Thumbprint: {1}" -f $cert.PSComputerName, $cert.Thumbprint | Trace-Output -Level:Warning } + + Write-Host "" # insert empty line for better readability } # restart nchostagent on server diff --git a/src/modules/SdnDiag.Utilities/Confirm-IsAdmin.ps1 b/src/modules/SdnDiag.Utilities/Confirm-IsAdmin.ps1 new file mode 100644 index 00000000..7cf6958f --- /dev/null +++ b/src/modules/SdnDiag.Utilities/Confirm-IsAdmin.ps1 @@ -0,0 +1,7 @@ +function Confirm-IsAdmin { + # ensure that the module is running as local administrator + $elevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + if (-NOT $elevated) { + throw New-Object System.Exception("This function requires elevated permissions. Run PowerShell as an Administrator and import the module again.") + } +} diff --git a/src/modules/SdnDiag.Utilities/private/Confirm-IsNetworkController.ps1 b/src/modules/SdnDiag.Utilities/private/Confirm-IsNetworkController.ps1 new file mode 100644 index 00000000..f1d3d76b --- /dev/null +++ b/src/modules/SdnDiag.Utilities/private/Confirm-IsNetworkController.ps1 @@ -0,0 +1,7 @@ +function Confirm-IsNetworkController { + $config = Get-SdnModuleConfiguration -Role 'NetworkController' + $confirmFeatures = Confirm-RequiredFeaturesInstalled -Name $config.windowsFeature + if (-NOT ($confirmFeatures)) { + throw New-Object System.NotSupportedException("The current machine is not a NetworkController, run this on NetworkController or use -NetworkController parameter (if available).") + } +} diff --git a/src/modules/SdnDiag.Utilities/private/Export-ObjectToFile.ps1 b/src/modules/SdnDiag.Utilities/private/Export-ObjectToFile.ps1 index 63678a82..f275f696 100644 --- a/src/modules/SdnDiag.Utilities/private/Export-ObjectToFile.ps1 +++ b/src/modules/SdnDiag.Utilities/private/Export-ObjectToFile.ps1 @@ -87,6 +87,7 @@ function Export-ObjectToFile { } catch { $_ | Trace-Exception + $_ | Write-Error } } } diff --git a/src/modules/SdnDiag.Utilities/public/Get-SdnModuleConfiguration.ps1 b/src/modules/SdnDiag.Utilities/public/Get-SdnModuleConfiguration.ps1 index 3556d7d9..f8b28669 100644 --- a/src/modules/SdnDiag.Utilities/public/Get-SdnModuleConfiguration.ps1 +++ b/src/modules/SdnDiag.Utilities/public/Get-SdnModuleConfiguration.ps1 @@ -15,7 +15,6 @@ function Get-SdnModuleConfiguration { $path = "SdnDiag.{0}\SdnDiag.{0}.Config.psd1" -f $Role $moduleConfig = Get-Item -Path $PSScriptRoot\..\$path -ErrorAction SilentlyContinue if ($moduleConfig) { - "Reading configuration data from {0}" -f $moduleConfig.FullName | Trace-Output -Level:Verbose $configurationData = Import-PowerShellDataFile -Path $moduleConfig.FullName }