├── .gitignore ├── Get-NetView.psd1 ├── Get-NetView.psm1 ├── LICENSE ├── README.md ├── SECURITY.md ├── appveyor.yml └── tests ├── results └── TestResults.xml ├── setup ├── deploy.ps1 ├── initiate-tests.ps1 └── install.ps1 └── unit └── unit.tests.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | DSCResource.Tests/ 3 | published/ 4 | 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | ## 8 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 9 | 10 | # User-specific files 11 | *.rsuser 12 | *.suo 13 | *.user 14 | *.userosscache 15 | *.sln.docstates 16 | 17 | # User-specific files (MonoDevelop/Xamarin Studio) 18 | *.userprefs 19 | 20 | # Mono auto generated files 21 | mono_crash.* 22 | 23 | # Build results 24 | [Dd]ebug/ 25 | [Dd]ebugPublic/ 26 | [Rr]elease/ 27 | [Rr]eleases/ 28 | x64/ 29 | x86/ 30 | [Ww][Ii][Nn]32/ 31 | [Aa][Rr][Mm]/ 32 | [Aa][Rr][Mm]64/ 33 | bld/ 34 | [Bb]in/ 35 | [Oo]bj/ 36 | [Ll]og/ 37 | [Ll]ogs/ 38 | 39 | # Visual Studio 2015/2017 cache/options directory 40 | .vs/ 41 | # Uncomment if you have tasks that create the project's static files in wwwroot 42 | #wwwroot/ 43 | 44 | # Visual Studio 2017 auto generated files 45 | Generated\ Files/ 46 | 47 | # MSTest test Results 48 | [Tt]est[Rr]esult*/ 49 | [Bb]uild[Ll]og.* 50 | 51 | # NUnit 52 | *.VisualState.xml 53 | TestResult.xml 54 | nunit-*.xml 55 | 56 | # Build Results of an ATL Project 57 | [Dd]ebugPS/ 58 | [Rr]eleasePS/ 59 | dlldata.c 60 | 61 | # Benchmark Results 62 | BenchmarkDotNet.Artifacts/ 63 | 64 | # .NET Core 65 | project.lock.json 66 | project.fragment.lock.json 67 | artifacts/ 68 | 69 | # ASP.NET Scaffolding 70 | ScaffoldingReadMe.txt 71 | 72 | # StyleCop 73 | StyleCopReport.xml 74 | 75 | # Files built by Visual Studio 76 | *_i.c 77 | *_p.c 78 | *_h.h 79 | *.ilk 80 | *.meta 81 | *.obj 82 | *.iobj 83 | *.pch 84 | *.pdb 85 | *.ipdb 86 | *.pgc 87 | *.pgd 88 | *.rsp 89 | *.sbr 90 | *.tlb 91 | *.tli 92 | *.tlh 93 | *.tmp 94 | *.tmp_proj 95 | *_wpftmp.csproj 96 | *.log 97 | *.vspscc 98 | *.vssscc 99 | .builds 100 | *.pidb 101 | *.svclog 102 | *.scc 103 | 104 | # Chutzpah Test files 105 | _Chutzpah* 106 | 107 | # Visual C++ cache files 108 | ipch/ 109 | *.aps 110 | *.ncb 111 | *.opendb 112 | *.opensdf 113 | *.sdf 114 | *.cachefile 115 | *.VC.db 116 | *.VC.VC.opendb 117 | 118 | # Visual Studio profiler 119 | *.psess 120 | *.vsp 121 | *.vspx 122 | *.sap 123 | 124 | # Visual Studio Trace Files 125 | *.e2e 126 | 127 | # TFS 2012 Local Workspace 128 | $tf/ 129 | 130 | # Guidance Automation Toolkit 131 | *.gpState 132 | 133 | # ReSharper is a .NET coding add-in 134 | _ReSharper*/ 135 | *.[Rr]e[Ss]harper 136 | *.DotSettings.user 137 | 138 | # TeamCity is a build add-in 139 | _TeamCity* 140 | 141 | # DotCover is a Code Coverage Tool 142 | *.dotCover 143 | 144 | # AxoCover is a Code Coverage Tool 145 | .axoCover/* 146 | !.axoCover/settings.json 147 | 148 | # Coverlet is a free, cross platform Code Coverage Tool 149 | coverage*[.json, .xml, .info] 150 | 151 | # Visual Studio code coverage results 152 | *.coverage 153 | *.coveragexml 154 | 155 | # NCrunch 156 | _NCrunch_* 157 | .*crunch*.local.xml 158 | nCrunchTemp_* 159 | 160 | # MightyMoose 161 | *.mm.* 162 | AutoTest.Net/ 163 | 164 | # Web workbench (sass) 165 | .sass-cache/ 166 | 167 | # Installshield output folder 168 | [Ee]xpress/ 169 | 170 | # DocProject is a documentation generator add-in 171 | DocProject/buildhelp/ 172 | DocProject/Help/*.HxT 173 | DocProject/Help/*.HxC 174 | DocProject/Help/*.hhc 175 | DocProject/Help/*.hhk 176 | DocProject/Help/*.hhp 177 | DocProject/Help/Html2 178 | DocProject/Help/html 179 | 180 | # Click-Once directory 181 | publish/ 182 | 183 | # Publish Web Output 184 | *.[Pp]ublish.xml 185 | *.azurePubxml 186 | # Note: Comment the next line if you want to checkin your web deploy settings, 187 | # but database connection strings (with potential passwords) will be unencrypted 188 | *.pubxml 189 | *.publishproj 190 | 191 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 192 | # checkin your Azure Web App publish settings, but sensitive information contained 193 | # in these scripts will be unencrypted 194 | PublishScripts/ 195 | 196 | # NuGet Packages 197 | *.nupkg 198 | # NuGet Symbol Packages 199 | *.snupkg 200 | # The packages folder can be ignored because of Package Restore 201 | **/[Pp]ackages/* 202 | # except build/, which is used as an MSBuild target. 203 | !**/[Pp]ackages/build/ 204 | # Uncomment if necessary however generally it will be regenerated when needed 205 | #!**/[Pp]ackages/repositories.config 206 | # NuGet v3's project.json files produces more ignorable files 207 | *.nuget.props 208 | *.nuget.targets 209 | 210 | # Microsoft Azure Build Output 211 | csx/ 212 | *.build.csdef 213 | 214 | # Microsoft Azure Emulator 215 | ecf/ 216 | rcf/ 217 | 218 | # Windows Store app package directories and files 219 | AppPackages/ 220 | BundleArtifacts/ 221 | Package.StoreAssociation.xml 222 | _pkginfo.txt 223 | *.appx 224 | *.appxbundle 225 | *.appxupload 226 | 227 | # Visual Studio cache files 228 | # files ending in .cache can be ignored 229 | *.[Cc]ache 230 | # but keep track of directories ending in .cache 231 | !?*.[Cc]ache/ 232 | 233 | # Others 234 | ClientBin/ 235 | ~$* 236 | *~ 237 | *.dbmdl 238 | *.dbproj.schemaview 239 | *.jfm 240 | *.pfx 241 | *.publishsettings 242 | orleans.codegen.cs 243 | 244 | # Including strong name files can present a security risk 245 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 246 | #*.snk 247 | 248 | # Since there are multiple workflows, uncomment next line to ignore bower_components 249 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 250 | #bower_components/ 251 | 252 | # RIA/Silverlight projects 253 | Generated_Code/ 254 | 255 | # Backup & report files from converting an old project file 256 | # to a newer Visual Studio version. Backup files are not needed, 257 | # because we have git ;-) 258 | _UpgradeReport_Files/ 259 | Backup*/ 260 | UpgradeLog*.XML 261 | UpgradeLog*.htm 262 | ServiceFabricBackup/ 263 | *.rptproj.bak 264 | 265 | # SQL Server files 266 | *.mdf 267 | *.ldf 268 | *.ndf 269 | 270 | # Business Intelligence projects 271 | *.rdl.data 272 | *.bim.layout 273 | *.bim_*.settings 274 | *.rptproj.rsuser 275 | *- [Bb]ackup.rdl 276 | *- [Bb]ackup ([0-9]).rdl 277 | *- [Bb]ackup ([0-9][0-9]).rdl 278 | 279 | # Microsoft Fakes 280 | FakesAssemblies/ 281 | 282 | # GhostDoc plugin setting file 283 | *.GhostDoc.xml 284 | 285 | # Node.js Tools for Visual Studio 286 | .ntvs_analysis.dat 287 | node_modules/ 288 | 289 | # Visual Studio 6 build log 290 | *.plg 291 | 292 | # Visual Studio 6 workspace options file 293 | *.opt 294 | 295 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 296 | *.vbw 297 | 298 | # Visual Studio LightSwitch build output 299 | **/*.HTMLClient/GeneratedArtifacts 300 | **/*.DesktopClient/GeneratedArtifacts 301 | **/*.DesktopClient/ModelManifest.xml 302 | **/*.Server/GeneratedArtifacts 303 | **/*.Server/ModelManifest.xml 304 | _Pvt_Extensions 305 | 306 | # Paket dependency manager 307 | .paket/paket.exe 308 | paket-files/ 309 | 310 | # FAKE - F# Make 311 | .fake/ 312 | 313 | # CodeRush personal settings 314 | .cr/personal 315 | 316 | # Python Tools for Visual Studio (PTVS) 317 | __pycache__/ 318 | *.pyc 319 | 320 | # Cake - Uncomment if you are using it 321 | # tools/** 322 | # !tools/packages.config 323 | 324 | # Tabs Studio 325 | *.tss 326 | 327 | # Telerik's JustMock configuration file 328 | *.jmconfig 329 | 330 | # BizTalk build output 331 | *.btp.cs 332 | *.btm.cs 333 | *.odx.cs 334 | *.xsd.cs 335 | 336 | # OpenCover UI analysis results 337 | OpenCover/ 338 | 339 | # Azure Stream Analytics local run output 340 | ASALocalRun/ 341 | 342 | # MSBuild Binary and Structured Log 343 | *.binlog 344 | 345 | # NVidia Nsight GPU debugger configuration file 346 | *.nvuser 347 | 348 | # MFractors (Xamarin productivity tool) working folder 349 | .mfractor/ 350 | 351 | # Local History for Visual Studio 352 | .localhistory/ 353 | 354 | # BeatPulse healthcheck temp database 355 | healthchecksdb 356 | 357 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 358 | MigrationBackup/ 359 | 360 | # Ionide (cross platform F# VS Code tools) working folder 361 | .ionide/ 362 | 363 | # Fody - auto-generated XML schema 364 | FodyWeavers.xsd 365 | -------------------------------------------------------------------------------- /Get-NetView.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'Get-NetView' 3 | # 4 | # Generated by: Dan Cuomo Trent Helms 5 | # 6 | # Generated on: 2/26/2025 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'Get-NetView.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '2025.2.26.254' 16 | 17 | # Supported PSEditions 18 | CompatiblePSEditions = 'Desktop', 'Core' 19 | 20 | # ID used to uniquely identify this module 21 | GUID = '72f13048-50c0-44fd-b7f1-369e98319092' 22 | 23 | # Author of this module 24 | Author = 'Dan Cuomo Trent Helms' 25 | 26 | # Company or vendor of this module 27 | CompanyName = 'Microsoft' 28 | 29 | # Copyright statement for this module 30 | Copyright = '(c) 2025 Inc. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = 'Get-NetView is a tool used to simplify the collection of network configuration information for diagnosis of networking issues on Windows' 34 | 35 | # Minimum version of the Windows PowerShell engine required by this module 36 | PowerShellVersion = '5.1' 37 | 38 | # Name of the Windows PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the Windows PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | # DotNetFrameworkVersion = '' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # CLRVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | # RequiredModules = @() 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | # FormatsToProcess = @() 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | # NestedModules = @() 70 | 71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 72 | FunctionsToExport = 'Get-NetView' 73 | 74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 75 | CmdletsToExport = @() 76 | 77 | # Variables to export from this module 78 | VariablesToExport = '*' 79 | 80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 81 | AliasesToExport = @() 82 | 83 | # DSC resources to export from this module 84 | # DscResourcesToExport = @() 85 | 86 | # List of all modules packaged with this module 87 | # ModuleList = @() 88 | 89 | # List of all files packaged with this module 90 | # FileList = @() 91 | 92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 93 | PrivateData = @{ 94 | 95 | PSData = @{ 96 | 97 | # Tags applied to this module. These help with module discovery in online galleries. 98 | Tags = 'MSFTNet' 99 | 100 | # A URL to the license for this module. 101 | # LicenseUri = '' 102 | 103 | # A URL to the main website for this project. 104 | ProjectUri = 'https://github.com/microsoft/Get-NetView' 105 | 106 | # A URL to an icon representing this module. 107 | # IconUri = '' 108 | 109 | # ReleaseNotes of this module 110 | # ReleaseNotes = '' 111 | 112 | # Prerelease string of this module 113 | # Prerelease = '' 114 | 115 | # Flag to indicate whether the module requires explicit user acceptance for install/update 116 | # RequireLicenseAcceptance = $false 117 | 118 | # External dependent modules of this module 119 | # ExternalModuleDependencies = @() 120 | 121 | } # End of PSData hashtable 122 | 123 | } # End of PrivateData hashtable 124 | 125 | # HelpInfo URI of this module 126 | # HelpInfoURI = '' 127 | 128 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 129 | # DefaultCommandPrefix = '' 130 | 131 | } 132 | 133 | -------------------------------------------------------------------------------- /Get-NetView.psm1: -------------------------------------------------------------------------------- 1 | $Global:Version = "2025.2.26.254" 2 | 3 | $Script:RunspacePool = $null 4 | $Script:ThreadList = [Collections.ArrayList]@() 5 | 6 | $Global:QueueActivity = "Queueing tasks..." 7 | $Global:FinishActivity = "Finishing..." 8 | 9 | $Global:ChelsioDeviceDirs = @{} 10 | $Global:MellanoxSystemLogDir = "" 11 | 12 | $ExecFunctions = { 13 | param( 14 | [parameter(Mandatory=$true)] [Hashtable] $ExecParams 15 | ) 16 | 17 | $columns = 4096 18 | 19 | # Alias Write-CmdLog to Write-Host for background threads, 20 | # since console color only applies to the main thread. 21 | Set-Alias -Name Write-CmdLog -Value Write-Host 22 | 23 | <# 24 | .SYNOPSIS 25 | Log control path errors or issues. 26 | #> 27 | function ExecControlError { 28 | [CmdletBinding()] 29 | Param( 30 | [parameter(Mandatory=$true)] [String] $OutDir, 31 | [parameter(Mandatory=$true)] [String] $Message 32 | ) 33 | 34 | $callerName = (Get-PSCallStack)[1].FunctionName 35 | 36 | $file = "_Error.$callerName.txt" 37 | $out = Join-Path $OutDir $file 38 | Write-Output $Message | Out-File -Encoding "default" -Width $columns -Append $out 39 | } # ExecControlError() 40 | 41 | enum CommandStatus { 42 | NotRun # The command was not executed 43 | Unavailable # [Part of] the command doesn't exist 44 | Failed # An error prevented successful execution 45 | Success # No errors or exceptions 46 | } 47 | 48 | # Powershell cmdlets have inconsistent implementations in command error handling. This function 49 | # performs a validation of the command prior to formal execution and will log any failures. 50 | function TestCommand { 51 | [CmdletBinding()] 52 | Param( 53 | [parameter(Mandatory=$true)] [String] $Command 54 | ) 55 | 56 | $status = [CommandStatus]::NotRun 57 | $duration = [TimeSpan]::Zero 58 | $commandOut = "" 59 | 60 | # Check timeout 61 | $delta = (Get-Date) - $ExecParams.StartTime 62 | if ($delta.TotalMinutes -gt $ExecParams.Timeout) { 63 | return $status, $duration.TotalMilliseconds, $commandOut 64 | } 65 | 66 | try { 67 | $error.Clear() 68 | 69 | # Redirect all command output (expect errors) to stdout. 70 | # Any errors will still be output to $error variable. 71 | $silentCmd = '$({0}) 2>$null 3>&1 4>&1 5>&1 6>&1' -f $Command 72 | 73 | $duration = Measure-Command { 74 | # ErrorAction MUST be Stop for try catch to work. 75 | $commandOut = (Invoke-Expression $silentCmd -ErrorAction Stop) 76 | } 77 | 78 | # Sometimes commands output errors even on successful execution. 79 | # We only should fail commands if an error was their *only* output. 80 | if (($error -ne $null) -and [String]::IsNullOrWhiteSpace($commandOut)) { 81 | # Some PS commands are incorrectly implemented in return 82 | # code and require detecting SilentlyContinue 83 | if ($Command -notlike "*SilentlyContinue*") { 84 | throw $error[0] 85 | } 86 | } 87 | 88 | $status = [CommandStatus]::Success 89 | } catch [Management.Automation.CommandNotFoundException] { 90 | $status = [CommandStatus]::Unavailable 91 | } catch { 92 | $status = [CommandStatus]::Failed 93 | $commandOut = ($_ | Out-String) 94 | } finally { 95 | # Post-execution cleanup to avoid false positives 96 | $error.Clear() 97 | } 98 | 99 | return $status, $duration.TotalMilliseconds, $commandOut 100 | } # TestCommand() 101 | 102 | function CreateZip { 103 | [CmdletBinding()] 104 | Param( 105 | [parameter(Mandatory=$true)] [String] $Src, 106 | [parameter(Mandatory=$true)] [String] $Out 107 | ) 108 | 109 | if (Test-path $Out) { 110 | Remove-item $Out 111 | } 112 | 113 | Add-Type -assembly "system.io.compression.filesystem" 114 | [io.compression.zipfile]::CreateFromDirectory($Src, $Out) 115 | } # CreateZip() 116 | 117 | function ExecCommand { 118 | [CmdletBinding()] 119 | Param( 120 | [parameter(Mandatory=$true)] [String] $Command 121 | ) 122 | 123 | $status, [Int] $duration, $commandOut = TestCommand -Command $Command 124 | 125 | # Mirror command execution context 126 | Write-Output "$env:USERNAME @ ${env:COMPUTERNAME}:" 127 | 128 | # Mirror command to execute 129 | Write-Output "$(prompt)$Command" 130 | 131 | $logPrefix = "({0,6:n0} ms)" -f $duration 132 | if ($status -ne [CommandStatus]::Success) { 133 | $logPrefix = "$logPrefix [$status]" 134 | Write-Output "[$status]" 135 | } 136 | Write-Output $commandOut 137 | 138 | Write-CmdLog "$logPrefix $Command" 139 | 140 | if ($ExecParams.DelayFactor -gt 0) { 141 | Start-Sleep -Milliseconds ($duration * $ExecParams.DelayFactor + 0.50) # round up 142 | } 143 | } # ExecCommand() 144 | 145 | function ExecCommands { 146 | [CmdletBinding()] 147 | Param( 148 | [parameter(Mandatory=$true)] [String] $File, 149 | [parameter(Mandatory=$true)] [String] $OutDir, 150 | [parameter(Mandatory=$true)] [String[]] $Commands 151 | ) 152 | 153 | $out = (Join-Path -Path $OutDir -ChildPath $File) 154 | $($Commands | foreach {ExecCommand -Command $_}) | Out-File -Encoding "default" -Width $columns -Append $out 155 | 156 | # With high-concurreny, WMI-based cmdlets sometimes output in an 157 | # incorrect format or with missing fields. Somehow, this helps 158 | # reduce the frequency of the problem. 159 | $null = Get-NetAdapter 160 | } # ExecCommands() 161 | } # $ExecFunctions 162 | 163 | <# 164 | .SYNOPSIS 165 | Create a shortcut file (.LNK) pointing to $TargetPath. 166 | .NOTES 167 | Used to avoid duplicate effort in IHV commands, which are 168 | executed per NIC, but some data is per system/ASIC. 169 | #> 170 | function New-LnkShortcut { 171 | [CmdletBinding()] 172 | Param( 173 | [parameter(Mandatory=$true)] [String] $LnkFile, 174 | [parameter(Mandatory=$true)] [String] $TargetPath 175 | ) 176 | 177 | if ($LnkFile -notlike "*.lnk") { 178 | return 179 | } 180 | 181 | $shell = New-Object -ComObject "WScript.Shell" 182 | $lnk = $shell.CreateShortcut($LnkFile) 183 | $lnk.TargetPath = $TargetPath 184 | $null = $lnk.Save() 185 | $null = [Runtime.Interopservices.Marshal]::ReleaseComObject($shell) 186 | } # New-LnkShortcut() 187 | 188 | <# 189 | .SYNOPSIS 190 | Replaces invalid characters with a placeholder to make a 191 | valid directory or filename. 192 | .NOTES 193 | Do not pass in a path. It will replace '\' and '/'. 194 | #> 195 | function ConvertTo-Filename { 196 | [CmdletBinding()] 197 | Param( 198 | [parameter(Position=0, Mandatory=$true)] [String] $Filename 199 | ) 200 | 201 | $invalidChars = [System.IO.Path]::GetInvalidFileNameChars() -join "" 202 | return $Filename -replace "[$invalidChars]","_" 203 | } 204 | 205 | function TryCmd { 206 | [CmdletBinding()] 207 | Param( 208 | [parameter(Mandatory=$true)] [ScriptBlock] $ScriptBlock 209 | ) 210 | 211 | try { 212 | $out = &$ScriptBlock 213 | } catch { 214 | $out = $null 215 | } 216 | 217 | # Returning $null will cause foreach to iterate once 218 | # unless TryCmd call is in parentheses. 219 | if ($out -eq $null) { 220 | $out = @() 221 | } 222 | 223 | return $out 224 | } # TryCmd() 225 | 226 | function Write-CmdLog { 227 | [CmdletBinding()] 228 | Param( 229 | [parameter(Mandatory=$true)] [String] $CmdLog 230 | ) 231 | 232 | $logColor = [ConsoleColor]::White 233 | switch -Wildcard ($CmdLog) { 234 | "*``[Failed``]*" { 235 | $logColor = [ConsoleColor]::Yellow 236 | break 237 | } 238 | "*``[Unavailable``]*" { 239 | $logColor = [ConsoleColor]::DarkGray 240 | break 241 | } 242 | "*``[NotRun``]*" { 243 | $logColor = [ConsoleColor]::Gray 244 | break 245 | } 246 | } 247 | 248 | Write-Host $CmdLog -ForegroundColor $logColor 249 | } # Write-CmdLog() 250 | 251 | function Open-GlobalRunspacePool { 252 | [CmdletBinding()] 253 | Param( 254 | [parameter(Mandatory=$true)] [Int] $BackgroundThreads 255 | ) 256 | 257 | if ($BackgroundThreads -gt 0) { 258 | $Script:RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, $BackgroundThreads) 259 | $Script:RunspacePool.Open() 260 | } 261 | 262 | if ($BackgroundThreads -le 1) { 263 | Set-Alias ExecCommandsAsync ExecCommands 264 | $Global:QueueActivity = "Executing commands..." 265 | } 266 | } # Open-GlobalRunspacePool() 267 | 268 | function Close-GlobalRunspacePool { 269 | [CmdletBinding()] 270 | Param() 271 | 272 | if ($Script:RunspacePool -ne $null) { 273 | Write-Progress -Activity $Global:FinishActivity -Status "Cleanup background threads..." 274 | 275 | if ($Script:ThreadList.Count -gt 0) { 276 | # Kill any DISM child process, which ignores below Stop attempt... 277 | $dismId = @(Get-CimInstance "Win32_Process" -Filter "Name = 'DismHost.exe' AND ParentProcessId = $PID").ProcessId 278 | if ($dismId.Count -gt 0) { 279 | Stop-Process -Id $dismId -Force 280 | } 281 | 282 | # Asyncronously stop all threads. 283 | $Script:ThreadList | foreach { 284 | $_.AsyncStop = $_.PowerShell.BeginStop($null, $_.AsyncInvoke) 285 | } 286 | 287 | # Wait for stops to complete. 288 | $Script:ThreadList | foreach { 289 | Write-CmdLog "( 0 ms) [NotRun] $($_.Command)" 290 | $_.PowerShell.EndStop($_.AsyncStop) 291 | } 292 | 293 | $Script:ThreadList.Clear() 294 | } 295 | 296 | $Script:RunspacePool.Close() 297 | $Script:RunspacePool.Dispose() 298 | $Script:RunspacePool = $null 299 | } 300 | } # Close-GlobalRunspacePool() 301 | 302 | function Start-Thread { 303 | [CmdletBinding()] 304 | Param( 305 | [parameter(Mandatory=$true)] [ScriptBlock] $ScriptBlock, 306 | [parameter(Mandatory=$false)] [Hashtable] $Params = @{} 307 | ) 308 | 309 | if ($null -eq $Script:RunspacePool) { 310 | # Execute command synchronously instead 311 | &$ScriptBlock @Params 312 | } else { 313 | $ps = [PowerShell]::Create() 314 | 315 | $ps.RunspacePool = $Script:RunspacePool 316 | $null = $ps.AddScript("Set-Location `"$(Get-Location)`"") 317 | $null = $ps.AddScript($ExecFunctions).AddParameter("ExecParams", $Global:ExecParams) 318 | $null = $ps.AddScript($ScriptBlock, $true).AddParameters($Params) 319 | 320 | $async = $ps.BeginInvoke() 321 | 322 | $cmd = if ($ScriptBlock -eq ${function:ExecCommands}) {$Params.Commands} else {$ScriptBlock.Ast.Name} 323 | 324 | $null = $Script:ThreadList.Add(@{AsyncInvoke=$async; Command=$cmd; PowerShell=$ps}) 325 | } 326 | } # Start-Thread() 327 | 328 | function Show-Threads { 329 | [CmdletBinding()] 330 | Param() 331 | 332 | $totalTasks = $Script:ThreadList.Count 333 | 334 | while ($Script:ThreadList.Count -gt 0) { 335 | Write-Progress -Activity "Waiting for all tasks to complete..." -Status "$($Script:ThreadList.Count) remaining." -PercentComplete (100 * (1 - $Script:ThreadList.Count / $totalTasks)) 336 | 337 | for ($i = 0; $i -lt $Script:ThreadList.Count; $i++) { 338 | $thread = $Script:ThreadList[$i] 339 | 340 | $thread.Powershell.Streams.Warning | Out-Host 341 | $thread.Powershell.Streams.Warning.Clear() 342 | $thread.Powershell.Streams.Information | foreach {Write-CmdLog "$_"} 343 | $thread.Powershell.Streams.Information.Clear() 344 | 345 | if ($thread.AsyncInvoke.IsCompleted) { 346 | # Accessing Streams.Error blocks until thread is completed 347 | $thread.Powershell.Streams.Error | Out-Host 348 | $thread.Powershell.Streams.Error.Clear() 349 | 350 | $thread.PowerShell.EndInvoke($thread.AsyncInvoke) 351 | $Script:ThreadList.RemoveAt($i) 352 | $i-- 353 | } 354 | } 355 | 356 | $delta = (Get-Date) - $Global:ExecParams.StartTime 357 | if ($delta.TotalMinutes -gt $Global:ExecParams.Timeout) { 358 | Write-Warning "Timeout was reached." 359 | break 360 | } 361 | 362 | Start-Sleep -Milliseconds 33 # ~30 Hz 363 | } 364 | } # Show-Threads() 365 | 366 | function ExecCommandsAsync { 367 | [CmdletBinding()] 368 | Param( 369 | [parameter(Mandatory=$true)] [String] $OutDir, 370 | [parameter(Mandatory=$true)] [String] $File, 371 | [parameter(Mandatory=$true)] [String[]] $Commands 372 | ) 373 | 374 | return Start-Thread -ScriptBlock ${function:ExecCommands} -Params $PSBoundParameters 375 | } # ExecCommandsAsync() 376 | 377 | function ExecCopyItemsAsync { 378 | [CmdletBinding()] 379 | Param( 380 | [parameter(Mandatory=$true)] [String] $OutDir, 381 | [parameter(Mandatory=$true)] [String] $File, 382 | [parameter(Mandatory=$true)] [String[]] $Paths, 383 | [parameter(Mandatory=$true)] [String] $Destination 384 | ) 385 | 386 | if (-not (Test-Path $Destination)) { 387 | $null = New-Item -ItemType "Container" -Path $Destination 388 | } 389 | 390 | [String[]] $cmds = $Paths | foreach {"Copy-Item -Path ""$_"" -Destination ""$Destination"" -Recurse -Verbose 4>&1"} 391 | return ExecCommandsAsync -OutDir $OutDir -File $File -Commands $cmds 392 | } # ExecCopyItemsAsync() 393 | 394 | # 395 | # Data Collection Functions 396 | # 397 | 398 | function NetIpNic { 399 | [CmdletBinding()] 400 | Param( 401 | [parameter(Mandatory=$false)] [String] $NicName, 402 | [parameter(Mandatory=$true)] [String] $OutDir 403 | ) 404 | 405 | $name = $NicName 406 | $dir = (Join-Path -Path $OutDir -ChildPath "NetIp") 407 | New-Item -ItemType directory -Path $dir | Out-Null 408 | 409 | $file = "Get-NetIpAddress.txt" 410 | [String []] $cmds = "Get-NetIpAddress -InterfaceAlias ""$name"" | Format-Table -AutoSize", 411 | "Get-NetIpAddress -InterfaceAlias ""$name"" | Format-Table -Property * -AutoSize", 412 | "Get-NetIpAddress -InterfaceAlias ""$name"" | Format-List", 413 | "Get-NetIpAddress -InterfaceAlias ""$name"" | Format-List -Property *" 414 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 415 | 416 | $file = "Get-NetIPInterface.txt" 417 | [String []] $cmds = "Get-NetIPInterface -InterfaceAlias ""$name""", 418 | "Get-NetIPInterface -InterfaceAlias ""$name"" | Format-Table -AutoSize", 419 | "Get-NetIPInterface -InterfaceAlias ""$name"" | Format-Table -Property * -AutoSize" 420 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 421 | 422 | $file = "Get-NetNeighbor.txt" 423 | [String []] $cmds = "Get-NetNeighbor -InterfaceAlias ""$name""", 424 | "Get-NetNeighbor -InterfaceAlias ""$name"" | Format-Table -AutoSize", 425 | "Get-NetNeighbor -InterfaceAlias ""$name"" | Format-Table -Property * -AutoSize" 426 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 427 | 428 | $file = "Get-NetRoute.txt" 429 | [String []] $cmds = "Get-NetRoute -InterfaceAlias ""$name"" | Format-Table -AutoSize", 430 | "Get-NetRoute -InterfaceAlias ""$name"" | Format-Table -Property * -AutoSize" 431 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 432 | } # NetIpNic() 433 | 434 | function NetIp { 435 | [CmdletBinding()] 436 | Param( 437 | [parameter(Mandatory=$true)] [String] $OutDir 438 | ) 439 | 440 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $($MyInvocation.MyCommand.Name)" 441 | 442 | $dir = (Join-Path -Path $OutDir -ChildPath "NetIp") 443 | New-Item -ItemType directory -Path $dir | Out-Null 444 | 445 | $file = "Get-NetIpAddress.txt" 446 | [String []] $cmds = "Get-NetIpAddress | Format-Table -AutoSize", 447 | "Get-NetIpAddress | Format-Table -Property * -AutoSize", 448 | "Get-NetIpAddress | Format-List", 449 | "Get-NetIpAddress | Format-List -Property *" 450 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 451 | 452 | $file = "Get-NetIPInterface.txt" 453 | [String []] $cmds = "Get-NetIPInterface", 454 | "Get-NetIPInterface | Format-Table -AutoSize", 455 | "Get-NetIPInterface | Format-Table -Property * -AutoSize" 456 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 457 | 458 | $file = "Get-NetNeighbor.txt" 459 | [String []] $cmds = "Get-NetNeighbor | Format-Table -AutoSize", 460 | "Get-NetNeighbor | Format-Table -Property * -AutoSize" 461 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 462 | 463 | $file = "Get-NetIPv4Protocol.txt" 464 | [String []] $cmds = "Get-NetIPv4Protocol", 465 | "Get-NetIPv4Protocol | Format-List -Property *", 466 | "Get-NetIPv4Protocol | Format-Table -Property * -AutoSize", 467 | "Get-NetIPv4Protocol | Format-Table -Property * -AutoSize" 468 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 469 | 470 | $file = "Get-NetIPv6Protocol.txt" 471 | [String []] $cmds = "Get-NetIPv6Protocol", 472 | "Get-NetIPv6Protocol | Format-List -Property *", 473 | "Get-NetIPv6Protocol | Format-Table -Property * -AutoSize", 474 | "Get-NetIPv6Protocol | Format-Table -Property * -AutoSize" 475 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 476 | 477 | $file = "Get-NetOffloadGlobalSetting.txt" 478 | [String []] $cmds = "Get-NetOffloadGlobalSetting", 479 | "Get-NetOffloadGlobalSetting | Format-List -Property *", 480 | "Get-NetOffloadGlobalSetting | Format-Table -AutoSize", 481 | "Get-NetOffloadGlobalSetting | Format-Table -Property * -AutoSize" 482 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 483 | 484 | $file = "Get-NetPrefixPolicy.txt" 485 | [String []] $cmds = "Get-NetPrefixPolicy | Format-Table -AutoSize", 486 | "Get-NetPrefixPolicy | Format-Table -Property * -AutoSize" 487 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 488 | 489 | $file = "Get-NetRoute.txt" 490 | [String []] $cmds = "Get-NetRoute | Format-Table -AutoSize", 491 | "Get-NetRoute | Format-Table -Property * -AutoSize" 492 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 493 | 494 | $file = "Get-NetTCPConnection.txt" 495 | [String []] $cmds = "Get-NetTCPConnection | Format-Table -AutoSize", 496 | "Get-NetTCPConnection | Format-Table -Property * -AutoSize" 497 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 498 | 499 | $file = "Get-NetTcpSetting.txt" 500 | [String []] $cmds = "Get-NetTcpSetting | Format-Table -AutoSize", 501 | "Get-NetTcpSetting | Format-Table -Property * -AutoSize", 502 | "Get-NetTcpSetting | Format-List -Property *" 503 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 504 | 505 | $file = "Get-NetTransportFilter.txt" 506 | [String []] $cmds = "Get-NetTransportFilter | Format-Table -AutoSize", 507 | "Get-NetTransportFilter | Format-Table -Property * -AutoSize", 508 | "Get-NetTransportFilter | Format-List -Property *" 509 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 510 | 511 | $file = "Get-NetUDPEndpoint.txt" 512 | [String []] $cmds = "Get-NetUDPEndpoint | Format-Table -AutoSize", 513 | "Get-NetUDPEndpoint | Format-Table -Property * -AutoSize" 514 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 515 | 516 | $file = "Get-NetUDPSetting.txt" 517 | [String []] $cmds = "Get-NetUDPSetting | Format-Table -AutoSize", 518 | "Get-NetUDPSetting | Format-Table -Property * -AutoSize" 519 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 520 | } # NetIp() 521 | 522 | function NetNatDetail { 523 | [CmdletBinding()] 524 | Param( 525 | [parameter(Mandatory=$true)] [String] $OutDir 526 | ) 527 | 528 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $($MyInvocation.MyCommand.Name)" 529 | 530 | $dir = (Join-Path -Path $OutDir -ChildPath "NetNat") 531 | New-Item -ItemType directory -Path $dir | Out-Null 532 | 533 | $file = "Get-NetNat.txt" 534 | [String []] $cmds = "Get-NetNat | Format-Table -AutoSize", 535 | "Get-NetNat | Format-Table -Property * -AutoSize", 536 | "Get-NetNat | Format-List", 537 | "Get-NetNat | Format-List -Property *" 538 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 539 | 540 | $file = "Get-NetNatExternalAddress.txt" 541 | [String []] $cmds = "Get-NetNatExternalAddress | Format-Table -AutoSize", 542 | "Get-NetNatExternalAddress | Format-Table -Property * -AutoSize", 543 | "Get-NetNatExternalAddress | Format-List", 544 | "Get-NetNatExternalAddress | Format-List -Property *" 545 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 546 | 547 | $file = "Get-NetNatGlobal.txt" 548 | [String []] $cmds = "Get-NetNatGlobal | Format-Table -AutoSize", 549 | "Get-NetNatGlobal | Format-Table -Property * -AutoSize", 550 | "Get-NetNatGlobal | Format-List", 551 | "Get-NetNatGlobal | Format-List -Property *" 552 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 553 | 554 | $file = "Get-NetNatSession.txt" 555 | [String []] $cmds = "Get-NetNatSession | Format-Table -AutoSize", 556 | "Get-NetNatSession | Format-Table -Property * -AutoSize", 557 | "Get-NetNatSession | Format-List", 558 | "Get-NetNatSession | Format-List -Property *" 559 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 560 | 561 | $file = "Get-NetNatStaticMapping.txt" 562 | [String []] $cmds = "Get-NetNatStaticMapping | Format-Table -AutoSize", 563 | "Get-NetNatStaticMapping | Format-Table -Property * -AutoSize", 564 | "Get-NetNatStaticMapping | Format-List", 565 | "Get-NetNatStaticMapping | Format-List -Property *" 566 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 567 | 568 | } # NetNat() 569 | 570 | function NetAdapterWorker { 571 | [CmdletBinding()] 572 | Param( 573 | [parameter(Mandatory=$false)] [String] $NicName, 574 | [parameter(Mandatory=$true)] [String] $OutDir 575 | ) 576 | 577 | $name = $NicName 578 | $dir = $OutDir 579 | 580 | $file = "nmbind.txt" 581 | [String []] $cmds = "nmbind ""$name"" " 582 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 583 | 584 | $file = "Get-NetAdapter.txt" 585 | [String []] $cmds = "Get-NetAdapter -Name ""$name"" -IncludeHidden", 586 | "Get-NetAdapter -Name ""$name"" -IncludeHidden | Format-List -Property *" 587 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 588 | 589 | $file = "Get-NetAdapterAdvancedProperty.txt" 590 | [String []] $cmds = "Get-NetAdapterAdvancedProperty -Name ""$name"" -AllProperties -IncludeHidden | Sort-Object RegistryKeyword | Format-Table -AutoSize", 591 | "Get-NetAdapterAdvancedProperty -Name ""$name"" -AllProperties -IncludeHidden | Format-List -Property *", 592 | "Get-NetAdapterAdvancedProperty -Name ""$name"" -AllProperties -IncludeHidden | Format-Table -Property *" 593 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 594 | 595 | $file = "Get-NetAdapterBinding.txt" 596 | [String []] $cmds = "Get-NetAdapterBinding -Name ""$name"" -AllBindings -IncludeHidden | Sort-Object ComponentID", 597 | "Get-NetAdapterBinding -Name ""$name"" -AllBindings -IncludeHidden | Format-List -Property *" 598 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 599 | 600 | $file = "Get-NetAdapterChecksumOffload.txt" 601 | [String []] $cmds = "Get-NetAdapterChecksumOffload -Name ""$name"" -IncludeHidden", 602 | "Get-NetAdapterChecksumOffload -Name ""$name"" -IncludeHidden | Format-List -Property *" 603 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 604 | 605 | $file = "Get-NetAdapterLso.txt" 606 | [String []] $cmds = "Get-NetAdapterLso -Name ""$name"" -IncludeHidden", 607 | "Get-NetAdapterLso -Name ""$name"" -IncludeHidden | Format-List -Property *" 608 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 609 | 610 | $file = "Get-NetAdapterRss.txt" 611 | [String []] $cmds = "Get-NetAdapterRss -Name ""$name"" -IncludeHidden", 612 | "Get-NetAdapterRss -Name ""$name"" -IncludeHidden | Format-List -Property *" 613 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 614 | 615 | $file = "Get-NetAdapterStatistics.txt" 616 | [String []] $cmds = "Get-NetAdapterStatistics -Name ""$name"" -IncludeHidden", 617 | "Get-NetAdapterStatistics -Name ""$name"" -IncludeHidden | Format-List -Property *" 618 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 619 | 620 | $file = "Get-NetAdapterEncapsulatedPacketTaskOffload.txt" 621 | [String []] $cmds = "Get-NetAdapterEncapsulatedPacketTaskOffload -Name ""$name"" -IncludeHidden", 622 | "Get-NetAdapterEncapsulatedPacketTaskOffload -Name ""$name"" -IncludeHidden | Format-List -Property *" 623 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 624 | 625 | $file = "Get-NetAdapterHardwareInfo.txt" 626 | [String []] $cmds = "Get-NetAdapterHardwareInfo -Name ""$name"" -IncludeHidden", 627 | "Get-NetAdapterHardwareInfo -Name ""$name"" -IncludeHidden | Format-List -Property *" 628 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 629 | 630 | $file = "Get-NetAdapterIPsecOffload.txt" 631 | [String []] $cmds = "Get-NetAdapterIPsecOffload -Name ""$name"" -IncludeHidden", 632 | "Get-NetAdapterIPsecOffload -Name ""$name"" -IncludeHidden | Format-List -Property *" 633 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 634 | 635 | $file = "Get-NetAdapterPowerManagement.txt" 636 | [String []] $cmds = "Get-NetAdapterPowerManagement -Name ""$name"" -IncludeHidden", 637 | "Get-NetAdapterPowerManagement -Name ""$name"" -IncludeHidden | Format-List -Property *" 638 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 639 | 640 | $file = "Get-NetAdapterQos.txt" 641 | [String []] $cmds = "Get-NetAdapterQos -Name ""$name"" -IncludeHidden", 642 | "Get-NetAdapterQos -Name ""$name"" -IncludeHidden | Format-List -Property *" 643 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 644 | 645 | $file = "Get-NetAdapterRdma.txt" 646 | [String []] $cmds = "Get-NetAdapterRdma -Name ""$name"" -IncludeHidden", 647 | "Get-NetAdapterRdma -Name ""$name"" -IncludeHidden | Format-List -Property *", 648 | "Get-NetAdapterRdma -Name ""$name"" -IncludeHidden | Select-Object -ExpandProperty RdmaAdapterInfo", 649 | "Get-NetAdapterRdma -Name ""$name"" -IncludeHidden | Select-Object -ExpandProperty RdmaMissingCounterInfo" 650 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 651 | 652 | $file = "Get-NetAdapterPacketDirect.txt" 653 | [String []] $cmds = "Get-NetAdapterPacketDirect -Name ""$name"" -IncludeHidden", 654 | "Get-NetAdapterPacketDirect -Name ""$name"" -IncludeHidden | Format-List -Property *" 655 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 656 | 657 | $file = "Get-NetAdapterRsc.txt" 658 | [String []] $cmds = "Get-NetAdapterRsc -Name ""$name"" -IncludeHidden", 659 | "Get-NetAdapterRsc -Name ""$name"" -IncludeHidden | Format-List -Property *" 660 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 661 | 662 | $file = "Get-NetAdapterSriov.txt" 663 | [String []] $cmds = "Get-NetAdapterSriov -Name ""$name"" -IncludeHidden", 664 | "Get-NetAdapterSriov -Name ""$name"" -IncludeHidden | Format-List -Property *" 665 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 666 | 667 | $file = "Get-NetAdapterSriovVf.txt" 668 | [String []] $cmds = "Get-NetAdapterSriovVf -Name ""$name"" -IncludeHidden", 669 | "Get-NetAdapterSriovVf -Name ""$name"" -IncludeHidden | Format-List -Property *" 670 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 671 | 672 | $file = "Get-NetAdapterUso.txt" 673 | [String []] $cmds = "Get-NetAdapterUso -Name ""$name"" -IncludeHidden", 674 | "Get-NetAdapterUso -Name ""$name"" -IncludeHidden | Format-List -Property *" 675 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 676 | 677 | $file = "Get-NetAdapterVmq.txt" 678 | [String []] $cmds = "Get-NetAdapterVmq -Name ""$name"" -IncludeHidden", 679 | "Get-NetAdapterVmq -Name ""$name"" -IncludeHidden | Format-List -Property *" 680 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 681 | 682 | $file = "Get-NetAdapterVmqQueue.txt" 683 | [String []] $cmds = "Get-NetAdapterVmqQueue -Name ""$name"" -IncludeHidden", 684 | "Get-NetAdapterVmqQueue -Name ""$name"" -IncludeHidden | Format-List -Property *" 685 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 686 | 687 | $file = "Get-NetAdapterVPort.txt" 688 | [String []] $cmds = "Get-NetAdapterVPort -Name ""$name"" -IncludeHidden", 689 | "Get-NetAdapterVPort -Name ""$name"" -IncludeHidden | Format-List -Property *" 690 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 691 | } # NetAdapterWorker() 692 | 693 | function NetAdapterWorkerPrepare { 694 | [CmdletBinding()] 695 | Param( 696 | [parameter(Mandatory=$false)] [String] $NicName, 697 | [ValidateSet("pNIC", "hNIC", "NIC")] 698 | [parameter(Mandatory=$true)] [String] $Type, 699 | [parameter(Mandatory=$true)] [String] $OutDir 700 | ) 701 | 702 | $name = $NicName 703 | $dir = $OutDir 704 | 705 | $script:NetAdapterTracker += $nic.ifIndex 706 | 707 | # Create dir for each NIC 708 | $nic = Get-NetAdapter -Name $name -IncludeHidden 709 | $idx = $nic.InterfaceIndex 710 | $desc = $nic.InterfaceDescription 711 | $title = "$Type.$idx.$name" 712 | 713 | if ("$desc") { 714 | $title = "$title.$desc" 715 | } 716 | 717 | if ($nic.Hidden) { 718 | $dir = Join-Path $dir "NIC.Hidden" 719 | } 720 | 721 | $dir = Join-Path $dir $(ConvertTo-Filename $title.Trim()) 722 | New-Item -ItemType directory -Path $dir | Out-Null 723 | 724 | Write-Progress $Global:QueueActivity -Status "Processing $title" 725 | NetIpNic -NicName $name -OutDir $dir 726 | NetAdapterWorker -NicName $name -OutDir $dir 727 | 728 | if ($Type -eq "pNIC") { 729 | NicVendor -NicName $name -OutDir $dir 730 | } elseif ($Type -eq "hNIC") { 731 | HostVNicWorker -DeviceID $nic.DeviceID -OutDir $dir 732 | } 733 | } # NetAdapterWorkerPrepare() 734 | 735 | function LbfoWorker { 736 | [CmdletBinding()] 737 | Param( 738 | [parameter(Mandatory=$false)] [String] $LbfoName, 739 | [parameter(Mandatory=$true)] [String] $OutDir 740 | ) 741 | 742 | $name = $LbfoName 743 | $title = "LBFO.$name" 744 | 745 | $Global:NetLbfoTracker += $LbfoName 746 | 747 | $dir = Join-Path $OutDir $(ConvertTo-Filename $title) 748 | New-Item -ItemType directory -Path $dir | Out-Null 749 | 750 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $title" 751 | $file = "Get-NetLbfoTeam.txt" 752 | [String []] $cmds = "Get-NetLbfoTeam -Name ""$name""", 753 | "Get-NetLbfoTeam -Name ""$name"" | Format-List -Property *" 754 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 755 | 756 | $file = "Get-NetLbfoTeamNic.txt" 757 | [String []] $cmds = "Get-NetLbfoTeamNic -Team ""$name""", 758 | "Get-NetLbfoTeamNic -Team ""$name"" | Format-List -Property *" 759 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 760 | 761 | $file = "Get-NetLbfoTeamMember.txt" 762 | [String []] $cmds = "Get-NetLbfoTeamMember -Team ""$name""", 763 | "Get-NetLbfoTeamMember -Team ""$name"" | Format-List -Property *" 764 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 765 | 766 | # Report the TNIC(S) 767 | foreach ($tnic in TryCmd {Get-NetLbfoTeamNic -Team $name}) { 768 | NetAdapterWorkerPrepare -NicName $tnic.Name -Type "NIC" -OutDir $OutDir 769 | } 770 | 771 | # Report the NIC Members 772 | foreach ($mnic in TryCmd {Get-NetLbfoTeamMember -Team $name}) { 773 | NetAdapterWorkerPrepare -NicName $mnic.Name -Type "NIC" -OutDir $OutDir 774 | } 775 | } # LbfoWorker() 776 | 777 | function LbfoDetail { 778 | [CmdletBinding()] 779 | Param( 780 | [parameter(Mandatory=$true)] [String] $OutDir 781 | ) 782 | 783 | $dir = $OutDir 784 | 785 | # Query remaining LBFO teams (non-Protocol NICs). 786 | $lbfoTeams = TryCmd {Get-NetLbfoTeam} | where {$_.Name -notin $script:NetLbfoTracker} 787 | foreach ($lbfo in $lbfoTeams) { 788 | LbfoWorker -LbfoName $lbfo.Name -OutDir $dir 789 | } 790 | } # LbfoDetail() 791 | 792 | function ProtocolNicDetail { 793 | [CmdletBinding()] 794 | Param( 795 | [parameter(Mandatory=$false)] [String] $VMSwitchId, 796 | [parameter(Mandatory=$true)] [String] $OutDir 797 | ) 798 | 799 | $id = $VMSwitchId 800 | $dir = $OutDir 801 | 802 | $vmsNicDescriptions = TryCmd {(Get-VMSwitch -Id $id).NetAdapterInterfaceDescriptions} 803 | foreach ($desc in $vmsNicDescriptions) { 804 | $nic = Get-NetAdapter -InterfaceDescription $desc 805 | if (-not $nic) { 806 | $msg = "No NetAdapter found with desciption ""$desc""." 807 | ExecControlError -OutDir $dir -Message $msg 808 | continue 809 | } 810 | 811 | if ($nic.DriverFileName -like "NdisImPlatform.sys") { 812 | LbfoWorker -LbfoName $nic.Name -OutDir $dir 813 | } else { 814 | NetAdapterWorkerPrepare -NicName $nic.Name -Type "pNIC" -OutDir $dir 815 | } 816 | } 817 | } # ProtocolNicDetail() 818 | 819 | function NativeNicDetail { 820 | [CmdletBinding()] 821 | Param( 822 | [parameter(Mandatory=$true)] [String] $OutDir 823 | ) 824 | 825 | $dir = $OutDir 826 | 827 | # Query all remaining NetAdapters 828 | $nics = Get-NetAdapter -IncludeHidden | where {$_.ifIndex -notin $script:NetAdapterTracker} 829 | foreach ($nic in $nics) { 830 | $type = if (Get-NetAdapterHardwareInfo -Name $nic.Name -IncludeHidden -ErrorAction "SilentlyContinue") {"pNIC"} else {"NIC"} 831 | NetAdapterWorkerPrepare -NicName $nic.Name -Type $type -OutDir $dir 832 | } 833 | } # NativeNicDetail() 834 | 835 | function NicDetail { 836 | # Track which NICs or LBFO teams have been queried. 837 | $script:NetAdapterTracker = @() 838 | $script:NetLbfoTracker = @() 839 | 840 | # These functions must be called in the correct order. 841 | VMSwitchDetail -OutDir $workDir 842 | LbfoDetail -OutDir $workDir 843 | NativeNicDetail -OutDir $workDir 844 | } # NicDetail() 845 | 846 | function ChelsioDetailPerASIC { 847 | [CmdletBinding()] 848 | Param( 849 | [parameter(Mandatory=$false)] [String] $NicName, 850 | [parameter(Mandatory=$true)] [String] $OutDir 851 | ) 852 | 853 | $hwInfo = Get-NetAdapterHardwareInfo -Name "$NicName" 854 | $locationInfo = $hwInfo.LocationInformationString 855 | $dirBusName = "BusDev_$($hwInfo.BusNumber)_$($hwInfo.DeviceNumber)_$($hwInfo.FunctionNumber)" 856 | $dir = Join-Path $OutDir $dirBusName 857 | 858 | if ($Global:ChelsioDeviceDirs.ContainsKey($locationInfo)) { 859 | New-LnkShortcut -LnkFile "$dir.lnk" -TargetPath $Global:ChelsioDeviceDirs[$locationInfo] 860 | return # avoid duplicate work 861 | } else { 862 | $Global:ChelsioDeviceDirs[$locationInfo] = $dir 863 | $null = New-Item -ItemType Directory -Path $dir 864 | } 865 | 866 | # Enumerate VBD 867 | $ifNameVbd = "" 868 | [Array] $PnPDevices = Get-PnpDevice -FriendlyName "*Chelsio*Enumerator*" | where {$_.Status -eq "OK"} 869 | for ($i = 0; $i -lt $PnPDevices.Count; $i++) { 870 | $instanceId = $PnPDevices[$i].InstanceId 871 | $locationInfo = (Get-PnpDeviceProperty -InstanceId "$instanceId" -KeyName "DEVPKEY_Device_LocationInfo").Data 872 | if ($hwInfo.LocationInformationString -eq $locationInfo) { 873 | $ifNameVbd = "vbd$i" 874 | break 875 | } 876 | } 877 | 878 | if ([String]::IsNullOrEmpty($ifNameVbd)) { 879 | $msg = "No bus device found for NIC ""$NicName""." 880 | ExecControlError -OutDir $dir -Message $msg 881 | return 882 | } 883 | 884 | $file = "ChelsioDetail-Firmware-BusDevice$i.txt" 885 | [String []] $cmds = "cxgbtool.exe $ifNameVbd firmware mbox 1", 886 | "cxgbtool.exe $ifNameVbd firmware mbox 2", 887 | "cxgbtool.exe $ifNameVbd firmware mbox 3", 888 | "cxgbtool.exe $ifNameVbd firmware mbox 4", 889 | "cxgbtool.exe $ifNameVbd firmware mbox 5", 890 | "cxgbtool.exe $ifNameVbd firmware mbox 6", 891 | "cxgbtool.exe $ifNameVbd firmware mbox 7" 892 | ExecCommands -OutDir $dir -File $file -Commands $cmds 893 | 894 | $file = "ChelsioDetail-Hardware-BusDevice$i.txt" 895 | [String []] $cmds = "cxgbtool.exe $ifNameVbd hardware sgedbg" 896 | ExecCommands -OutDir $dir -File $file -Commands $cmds 897 | 898 | $file = "ChelsioDetail-Dumps-BusDevice$i.txt" 899 | [String []] $cmds = "cxgbtool.exe $ifNameVbd hardware flash ""$dir\Hardware-BusDevice$i-flash.dmp""", 900 | "cxgbtool.exe $ifNameVbd cudbg collect all ""$dir\Cudbg-Collect.dmp""", 901 | "cxgbtool.exe $ifNameVbd cudbg readflash ""$dir\Cudbg-Readflash.dmp""" 902 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 903 | } # ChelsioDetailPerASIC() 904 | 905 | function ChelsioDetail { 906 | [CmdletBinding()] 907 | Param( 908 | [parameter(Mandatory=$false)] [String] $NicName, 909 | [parameter(Mandatory=$true)] [String] $OutDir 910 | ) 911 | 912 | $dir = (Join-Path -Path $OutDir -ChildPath "ChelsioDetail") 913 | New-Item -ItemType Directory -Path $dir | Out-Null 914 | 915 | $file = "ChelsioDetail-Misc.txt" 916 | [String []] $cmds = "verifier /query", 917 | "Get-PnpDevice -FriendlyName ""*Chelsio*Enumerator*"" | Get-PnpDeviceProperty -KeyName DEVPKEY_Device_DriverVersion | Format-Table -Autosize" 918 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 919 | 920 | $cxgbtoolTest = TryCmd {cxgbtool.exe} 921 | if (-not $cxgbtoolTest) { 922 | $msg = "cxgbtool is required to collect Chelsio diagnostics." 923 | ExecControlError -OutDir $dir -Message $msg 924 | return 925 | } 926 | 927 | ChelsioDetailPerASIC -NicName $NicName -OutDir $dir 928 | 929 | $ifIndex = (Get-NetAdapter $NicName).InterfaceIndex 930 | $dirNetName = "NetDev_$ifIndex" 931 | $dirNet = (Join-Path -Path $dir -ChildPath $dirNetName) 932 | New-Item -ItemType Directory -Path $dirNet | Out-Null 933 | 934 | # Enumerate NIC 935 | $netDevices = Get-NetAdapter -InterfaceDescription "*Chelsio*" | where {$_.Status -eq "Up"} | sort -Property MacAddress 936 | $nicIndex = @($netDevices.Name).IndexOf($NicName) 937 | 938 | if ($nicIndex -eq -1) { 939 | $msg = "Invalid state for NIC ""$NicName"". Make sure status is ""Up""." 940 | ExecControlError -OutDir $dir -Message $msg 941 | return 942 | } 943 | 944 | $file = "ChelsioDetail-Debug.txt" 945 | [String []] $cmds = "cxgbtool.exe nic$nicIndex debug filter", 946 | "cxgbtool.exe nic$nicIndex debug qsets", 947 | "cxgbtool.exe nic$nicIndex debug qstats txeth rxeth txvirt rxvirt txrdma rxrdma txnvgre rxnvgre", 948 | "cxgbtool.exe nic$nicIndex debug dumpctx", 949 | "cxgbtool.exe nic$nicIndex debug version", 950 | "cxgbtool.exe nic$nicIndex debug eps", 951 | "cxgbtool.exe nic$nicIndex debug qps", 952 | "cxgbtool.exe nic$nicIndex debug rdma_stats", 953 | "cxgbtool.exe nic$nicIndex debug stags", 954 | "cxgbtool.exe nic$nicIndex debug l2t" 955 | ExecCommandsAsync -OutDir $dirNet -File $file -Commands $cmds 956 | 957 | $file = "ChelsioDetail-Hardware.txt" 958 | [String []] $cmds = "cxgbtool.exe nic$nicIndex hardware tid_info", 959 | "cxgbtool.exe nic$nicIndex hardware fec", 960 | "cxgbtool.exe nic$nicIndex hardware link_cfg", 961 | "cxgbtool.exe nic$nicIndex hardware pktfilter", 962 | "cxgbtool.exe nic$nicIndex hardware sensor" 963 | ExecCommandsAsync -OutDir $dirNet -File $file -Commands $cmds 964 | } # ChelsioDetail() 965 | 966 | function MellanoxFirmwareInfo { 967 | [CmdletBinding()] 968 | Param( 969 | [parameter(Mandatory=$false)] [String] $NicName, 970 | [parameter(Mandatory=$true)] [String] $OutDir 971 | ) 972 | 973 | $dir = $OutDir 974 | 975 | $mstStatus = TryCmd {mst status -v} 976 | if ((-not $mstStatus) -or ($mstStatus -like "*error*")) { 977 | $msg = "Mellanox Firmware Tools (MFT) is required to collect firmware diagnostics." 978 | ExecControlError -OutDir $dir -Message $msg 979 | return 980 | } 981 | 982 | # 983 | # Parse "mst status" output and match to Nic 984 | # 985 | [Bool] $found = $false 986 | $hwInfo = Get-NetAdapterHardwareInfo -Name $NicName 987 | 988 | foreach ($line in ($mstStatus | where {$_ -like "*pciconf*"})) { 989 | $device, $info = $line.Trim() -split " " 990 | $busNum, $deviceNum, $functionNum = $info -split "[:.=]" | select -Last 3 | foreach {[Int64]"0x$_"} 991 | 992 | if (($hwInfo.Bus -eq $busNum) -and ($hwInfo.Device -eq $deviceNum) -and ($hwInfo.Function -eq $functionNum)) { 993 | $found = $true 994 | $device = $device.Trim() 995 | break 996 | } 997 | } 998 | 999 | if (-not $found) { 1000 | $msg = "No device found in mst status matching NIC ""$NicName""." 1001 | ExecControlError -OutDir $dir -Message $msg 1002 | return 1003 | } 1004 | 1005 | $deviceDir = Join-Path $dir "mstdump-$device" 1006 | $null = New-Item -ItemType Directory -Path $deviceDir 1007 | 1008 | $file = "MellanoxFirmwareInfo.txt" 1009 | [String[]] $cmds = "mst status", 1010 | "flint -d $device query", 1011 | "flint -d $device dc", 1012 | "mstdump $device >> ""$deviceDir\1.txt""", 1013 | "mstdump $device >> ""$deviceDir\2.txt""", 1014 | "mstdump $device >> ""$deviceDir\3.txt""", 1015 | "mlxconfig -d $device query", 1016 | "mlxdump -d $device fsdump --type FT" 1017 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1018 | } # MellanoxFirmwareInfo() 1019 | 1020 | function MellanoxWinOFTool{ 1021 | [CmdletBinding()] 1022 | Param( 1023 | [parameter(Mandatory=$false)] [String] $NicName, 1024 | [parameter(Mandatory=$true)] [String] $OutDir 1025 | ) 1026 | 1027 | $dir = $OutDir 1028 | 1029 | $toolName = "mlxtool.exe" 1030 | $toolPath = "$env:ProgramFiles\Mellanox\MLNX_VPI\Tools\$toolName" 1031 | $mlxTool = "&""$toolPath""" 1032 | 1033 | $hardwareInfo = Get-NetAdapterHardwareInfo -Name $NicName 1034 | $deviceLocation = "$($hardwareInfo.bus)`_$($hardwareInfo.device)`_$($hardwareInfo.function)" 1035 | 1036 | $toolCmds = "$mlxTool show ports", 1037 | "$mlxTool show devices", 1038 | "$mlxTool show tc-bw", 1039 | "$mlxTool show vxlan", 1040 | "$mlxTool show ecn config", 1041 | "$mlxTool show packet-filter", 1042 | "$mlxTool show qos", 1043 | "$mlxTool show regkeys all miniport", 1044 | "$mlxTool show regkeys all bus", 1045 | "$mlxTool show nd connections", 1046 | "$mlxTool show ndk connections", 1047 | "$mlxTool show perfstats ""$NicName"" showall", 1048 | "$mlxTool show driverparams", 1049 | "$mlxTool show selfhealing port", 1050 | "$mlxTool dbg oid-stats-ext", 1051 | "$mlxTool dbg cmd-stats-ext", 1052 | "$mlxTool dbg resources", 1053 | "$mlxTool dbg pkeys", 1054 | "$mlxTool dbg ipoib-ep", 1055 | "$mlxTool dbg get-state", 1056 | "$mlxTool dbg rfd-profiling ""$NicName"" dump", 1057 | "$mlxTool dbg pddrinfo", 1058 | "$mlxTool dbg dump-me-now", 1059 | "$mlxTool dbg eq-data ""$deviceLocation""", 1060 | "$mlxTool dbg dma-cached-stats ""$deviceLocation""" 1061 | 1062 | $file = "mlxtoolOutput.txt" 1063 | ExecCommandsAsync -OutDir $dir -File $file -Commands $toolCmds 1064 | 1065 | } # MellanoxWinOFTool 1066 | 1067 | function MellanoxDetailPerNic { 1068 | [CmdletBinding()] 1069 | Param( 1070 | [parameter(Mandatory=$false)] [String] $NicName, 1071 | [parameter(Mandatory=$true)] [String] $OutDir 1072 | ) 1073 | 1074 | $dir = $OutDir 1075 | 1076 | $driverFileName = (Get-NetAdapter -name $NicName).DriverFileName 1077 | $driverDir = switch ($driverFileName) { 1078 | "mlx5.sys" { 1079 | "$env:ProgramFiles\Mellanox\MLNX_WinOF2" 1080 | break 1081 | } 1082 | "mlnx5.sys" { 1083 | "$env:ProgramFiles\Mellanox\MLNX_WinOF2_Azure" 1084 | break 1085 | } 1086 | "mlnx5hpc.sys" { 1087 | "$env:ProgramFiles\Mellanox\MLNX_WinOF2_Azure_HPC" 1088 | break 1089 | } 1090 | "ipoib6x.sys" { 1091 | "$env:ProgramFiles\Mellanox\MLNX_VPI" 1092 | break 1093 | } 1094 | "mlx4eth63.sys" { 1095 | "$env:ProgramFiles\Mellanox\MLNX_VPI" 1096 | break 1097 | } 1098 | default { 1099 | $msg = "Unsupported driver $driverFileName." 1100 | ExecControlError -OutDir $dir -Message $msg 1101 | return 1102 | } 1103 | } 1104 | 1105 | # 1106 | # Execute tool 1107 | # 1108 | 1109 | $DriverName = $( if ($driverFileName -in @("Mlx5.sys", "Mlnx5.sys", "Mlnx5Hpc.sys")) {"WinOF2"} else {"WinOF"}) 1110 | if ($DriverName -eq "WinOF2") { 1111 | 1112 | $driverVersionString = (Get-NetAdapter -name $NicName).DriverVersionString 1113 | $versionMajor, $_ = $driverVersionString -split "\." 1114 | 1115 | if ($versionMajor -ge 3) { 1116 | $toolName = $driverFileName -replace ".sys", "Cmd" 1117 | $toolPath = "$driverDir\Management Tools\$toolName.exe" 1118 | 1119 | $file = "$toolName-Snapshot.txt" 1120 | [String []] $cmds = "&""$toolPath"" -SnapShot -name ""$NicName""" 1121 | $functionIds = (Get-NetAdapterSriovVf -Name "$NicName" -ErrorAction SilentlyContinue).FunctionID 1122 | if ($functionIds -ne $null) { 1123 | foreach ($id in $functionIds) { 1124 | $cmds += "&""$toolPath"" -SnapShot -VfStats -name ""$NicName"" -vf $id -register" 1125 | } 1126 | } 1127 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1128 | } 1129 | } else { 1130 | MellanoxWinOFTool -NicName $NicName -OutDir $Dir 1131 | } 1132 | 1133 | # 1134 | # Enumerate device location string 1135 | # 1136 | if ((Get-NetAdapterHardwareInfo -Name $NicName).LocationInformationString -like "*Virtual*") { 1137 | [String[]] $locationInfoArray = (Get-NetAdapterHardwareInfo -Name $NicName).LocationInformationString -split " " 1138 | 1139 | $slot = $locationInfoArray[$locationInfoArray.IndexOf("Slot") + 1] 1140 | $serial = $locationInfoArray[$locationInfoArray.IndexOf("Serial") + 1] 1141 | 1142 | $deviceLocation = "$slot`_$serial`_0" 1143 | } else { 1144 | $hardwareInfo = Get-NetAdapterHardwareInfo -Name $NicName 1145 | $deviceLocation = "$($hardwareInfo.bus)`_$($hardwareInfo.device)`_$($hardwareInfo.function)" 1146 | } 1147 | 1148 | # 1149 | # Dump Me Now (DMN) 1150 | # 1151 | $deviceID = (Get-NetAdapter -name $NicName).PnPDeviceID 1152 | $driverRegKey = (Get-ItemProperty "HKLM:\System\CurrentControlSet\Enum\$deviceID").Driver 1153 | $dumpMeNowDir = (Get-ItemProperty "HKLM:\System\CurrentControlSet\Control\Class\$driverRegKey").DumpMeNowDirectory 1154 | 1155 | if (($dumpMeNowDir -like "\DosDevice\*") -or ($dumpMeNowDir -like "\??\*")) { 1156 | $dmpPath = $dumpMeNowDir.SubString($dumpMeNowDir.IndexOf("\", 1)) 1157 | } else { 1158 | $dmpPath = "$env:windir\Temp\MLX{0}_Dump_Me_Now" -f $(if ($DriverName -eq "WinOF2") {"5"} else {"4"}) 1159 | } 1160 | 1161 | $file = "Copy-MellanoxDMN.txt" 1162 | [String[]] $paths = "$dmpPath{0}" -f $(if ($DriverName -eq "WinOF2") {("-" + $deviceLocation -replace "_","-")}) 1163 | ExecCopyItemsAsync -OutDir $dir -File $file -Paths $paths -Destination $dir 1164 | 1165 | # 1166 | # Device logs 1167 | # 1168 | 1169 | $file = "Copy-DeviceLogs.txt" 1170 | $destination = Join-Path $dir "DeviceLogs" 1171 | $buildIdPath = "$driverDir\build_id.txt" 1172 | 1173 | ExecCopyItemsAsync -OutDir $dir -File $file -Paths $buildIdPath -Destination $destination 1174 | 1175 | if ($DriverName -eq "WinOF2"){ 1176 | [String[]] $paths = "$env:windir\Temp\SingleFunc*$deviceLocation*.log", 1177 | "$env:windir\Temp\SriovMaster*$deviceLocation*.log", 1178 | "$env:windir\Temp\SriovSlave*$deviceLocation*.log", 1179 | "$env:windir\Temp\Native*$deviceLocation*.log", 1180 | "$env:windir\Temp\Master*$deviceLocation*.log", 1181 | "$env:windir\Temp\ML?X5*$deviceLocation*.log", 1182 | "$env:windir\Temp\mlx5*$deviceLocation*.log", 1183 | "$env:windir\Temp\FwTrace" 1184 | ExecCopyItemsAsync -OutDir $dir -File $file -Paths $paths -Destination $destination 1185 | } 1186 | } # MellanoxDetailPerNic() 1187 | 1188 | function MellanoxSystemDetail { 1189 | [CmdletBinding()] 1190 | Param( 1191 | [parameter(Mandatory=$false)] [String] $NicName, 1192 | [parameter(Mandatory=$true)] [String] $OutDir 1193 | ) 1194 | 1195 | $dir = Join-Path $OutDir "SystemLogs" 1196 | 1197 | if ([String]::IsNullOrEmpty($Global:MellanoxSystemLogDir)){ 1198 | $Global:MellanoxSystemLogDir = $dir 1199 | $null = New-Item -ItemType Directory -Path $dir 1200 | } else { 1201 | New-LnkShortcut -LnkFile "$dir.lnk" -TargetPath $Global:MellanoxSystemLogDir 1202 | return # avoid duplicate effort 1203 | } 1204 | 1205 | $file = "MellanoxMiscInfo.txt" 1206 | [String []] $cmds = "netsh advfirewall show allprofiles", 1207 | "netstat -n", 1208 | "netstat -nasert", 1209 | "netstat -an", 1210 | "netstat -xan | where {`$_ -match ""445""}", 1211 | "Get-SmbConnection", 1212 | "Get-SmbServerConfiguration" 1213 | ExecCommands -OutDir $dir -File $file -Commands $cmds 1214 | 1215 | $driverFileName = (Get-NetAdapter -name $NicName).DriverFileName 1216 | $DriverName = if ($driverFileName -in @("Mlx5.sys", "Mlnx5.sys", "Mlnx5Hpc.sys")) {"WinOF2"} else {"WinOF"} 1217 | 1218 | $file = "Copy-LogFiles.txt" 1219 | $destination = Join-Path $dir "LogFiles" 1220 | 1221 | $mlxEtl = "Mellanox{0}.etl*" -f $(if ($DriverName -eq "WinOF2") {"-WinOF2*"} else {"-System*"}) 1222 | $mlxLog = "MLNX_WINOF{0}.log" -f $(if ($DriverName -eq "WinOF2") {"2"}) 1223 | 1224 | [String[]] $paths = "$env:windir\System32\LogFiles\PerformanceTuning.log", 1225 | "$env:LOCALAPPDATA\$mlxLog", 1226 | "$env:windir\inf\setupapi.dev", 1227 | "$env:windir\inf\setupapi.dev.log", 1228 | "$env:temp\MpKdTraceLog.bin", 1229 | "$env:windir\System32\LogFiles\Mlnx\$mlxEtl", 1230 | "$env:windir\debug\$mlxEtl" 1231 | ExecCopyItemsAsync -OutDir $dir -File $file -Paths $paths -Destination $destination 1232 | } # MellanoxSystemDetail() 1233 | 1234 | function MellanoxDetail { 1235 | [CmdletBinding()] 1236 | Param( 1237 | [parameter(Mandatory=$false)] [String] $NicName, 1238 | [parameter(Mandatory=$true)] [String] $OutDir 1239 | ) 1240 | 1241 | $dir = (Join-Path -Path $OutDir -ChildPath "MellanoxDetail") 1242 | New-Item -ItemType Directory -Path $dir | Out-Null 1243 | 1244 | $driverVersionString = (Get-NetAdapter -name $NicName).DriverVersionString 1245 | $versionMajor, $versionMinor, $_ = $driverVersionString -split "\." 1246 | 1247 | if (($versionMajor -lt 2) -or (($versionMajor -eq 2) -and ($versionMinor -lt 20))) { 1248 | $msg = "Unsupported driver version $versionMajor.$versionMinor, minimum is 2.20." 1249 | ExecControlError -OutDir $dir -Message $msg 1250 | return 1251 | } 1252 | 1253 | MellanoxSystemDetail -NicName $NicName -OutDir $dir 1254 | MellanoxFirmwareInfo -NicName $NicName -OutDir $dir 1255 | MellanoxDetailPerNic -NicName $NicName -OutDir $dir 1256 | } # MellanoxDetail() 1257 | 1258 | function MarvellDetail{ 1259 | [CmdletBinding()] 1260 | Param( 1261 | [parameter(Mandatory=$true)] [String] $NicName, 1262 | [parameter(Mandatory=$true)] [String] $OutDir 1263 | ) 1264 | 1265 | $MarvellGetDiagDataClass = @" 1266 | using System; 1267 | using System.IO; 1268 | using System.Text; 1269 | using System.Runtime.InteropServices; 1270 | using Microsoft.Win32.SafeHandles; 1271 | 1272 | public class MarvellGetDiagData 1273 | { 1274 | private const uint QEBDRV_DIAG_IOC = 0x80002538; 1275 | private const uint EBDRV_DIAG_IOC = 0x80002130; 1276 | private const uint NIC_DIAG_IOC = 0x00170002; 1277 | private const uint L2ND2_DIAG_IOC = 0xFF010148; 1278 | private const uint QEBDRV_DIAG_MASK = 0xFFFDFF7F; 1279 | private const uint EBDRV_DIAG_MASK = 0xFFFFFFFF; 1280 | private const uint L2ND2_DIAG_MASK = 0xFFFFFFFF; 1281 | private const uint SIGNATURE = 0x4488AACC; 1282 | private const uint QEBDRV_DIAG_REVISION = 0x01; 1283 | private const uint EBDRV_DIAG_REVISION = 0x01; 1284 | private const uint L2ND2_DIAG_REVISION = 0x01; 1285 | 1286 | private const uint BYTE_SIZE = (9 * 1024 * 1024); 1287 | 1288 | [StructLayout(LayoutKind.Sequential)] 1289 | public struct DiagInput_t 1290 | { 1291 | public uint revision; 1292 | public uint data_mask; 1293 | public uint signature; 1294 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] 1295 | public int[] reserved; 1296 | } 1297 | 1298 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 1299 | private static extern SafeFileHandle CreateFile( 1300 | string lpFileName, 1301 | [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess, 1302 | [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, 1303 | IntPtr lpSecurityAttributes, 1304 | [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, 1305 | [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes, 1306 | IntPtr hTemplateFile); 1307 | 1308 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 1309 | private static extern bool DeviceIoControl( 1310 | SafeFileHandle hDevice, 1311 | uint IoControlCode, 1312 | byte[] InBuffer, 1313 | int nInBufferSize, 1314 | byte[] OutBuffer, 1315 | int nOutBufferSize, 1316 | ref int pBytesReturned, 1317 | IntPtr Overlapped 1318 | ); 1319 | 1320 | public int MarvellGetDiagDataIoctl(string DeviceID, string FilePath, string ServiceName, StringBuilder ErrString) 1321 | { 1322 | bool bResult; 1323 | string FileName; 1324 | uint revision_set; 1325 | uint data_mask_set; 1326 | uint ioctl_value; 1327 | string DevPath; 1328 | int bytesReturned = 0; 1329 | SafeFileHandle shwnd = null; 1330 | FileStream file = null; 1331 | 1332 | ErrString.Clear(); 1333 | 1334 | if ((DeviceID == null) || (FilePath == null)) 1335 | { 1336 | ErrString.Append("MarvellGetDiagDataIoctl: Input parameter to MarvellGetDiagDataIoctl is invalid"); 1337 | return 0; 1338 | } 1339 | 1340 | try 1341 | { 1342 | if (ServiceName.Equals("QEBDRV", StringComparison.OrdinalIgnoreCase)) 1343 | { 1344 | DevPath = "\\\\?\\Global\\" + DeviceID.Replace("\\", "#"); 1345 | DevPath += "#{5966d73c-bc2c-49b8-9315-c64c9919e976}"; 1346 | 1347 | ioctl_value = QEBDRV_DIAG_IOC; 1348 | revision_set = QEBDRV_DIAG_REVISION; 1349 | data_mask_set = QEBDRV_DIAG_MASK; 1350 | } 1351 | else if (ServiceName.Equals("EBDRV", StringComparison.OrdinalIgnoreCase)) 1352 | { 1353 | DevPath = "\\\\?\\Global\\" + DeviceID.Replace("\\", "#"); 1354 | DevPath += "#{ea22615e-c443-434f-9e45-c4e32d83e97d}"; 1355 | 1356 | ioctl_value = EBDRV_DIAG_IOC; 1357 | revision_set = EBDRV_DIAG_REVISION; 1358 | data_mask_set = EBDRV_DIAG_MASK; 1359 | } 1360 | else if (ServiceName.Equals("L2ND2", StringComparison.OrdinalIgnoreCase)) 1361 | { 1362 | DevPath = "\\\\.\\" + DeviceID.Replace("\\", "#"); 1363 | 1364 | ioctl_value = NIC_DIAG_IOC; 1365 | revision_set = L2ND2_DIAG_REVISION; 1366 | data_mask_set = L2ND2_DIAG_MASK; 1367 | } 1368 | else 1369 | { 1370 | ErrString.Append("MarvellGetDiagDataIoctl: Invalid or unsupported service (" + ServiceName + ")"); 1371 | return 0; 1372 | } 1373 | 1374 | ErrString.Append("MarvellGetDiagDataIoctl: " + DevPath + "\n"); 1375 | shwnd = CreateFile(DevPath, FileAccess.Write | FileAccess.Read, FileShare.Read | 1376 | FileShare.Write, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); 1377 | if (shwnd.IsClosed | shwnd.IsInvalid) 1378 | { 1379 | ErrString.Append("MarvellGetDiagDataIoctl: CreateFile failed with error " + Marshal.GetLastWin32Error()); 1380 | return 0; 1381 | } 1382 | 1383 | DiagInput_t DiagInput = new DiagInput_t 1384 | { 1385 | revision = revision_set, 1386 | data_mask = data_mask_set, 1387 | signature = SIGNATURE 1388 | }; 1389 | 1390 | int InBufLen = Marshal.SizeOf(); 1391 | IntPtr ptr = Marshal.AllocHGlobal(InBufLen); 1392 | Marshal.StructureToPtr(DiagInput, ptr, true); 1393 | 1394 | byte[] InBuffer; 1395 | byte[] OutBuffer = new byte[BYTE_SIZE]; 1396 | Array.Clear(OutBuffer, 0, OutBuffer.Length); 1397 | 1398 | if (ioctl_value == NIC_DIAG_IOC) 1399 | { 1400 | Marshal.Copy(ptr, OutBuffer, 0, InBufLen); 1401 | InBuffer = BitConverter.GetBytes(L2ND2_DIAG_IOC); 1402 | } 1403 | else 1404 | { 1405 | InBuffer = new byte[InBufLen]; 1406 | Marshal.Copy(ptr, InBuffer, 0, InBufLen); 1407 | } 1408 | Marshal.FreeHGlobal(ptr); 1409 | 1410 | bResult = DeviceIoControl(shwnd, ioctl_value, InBuffer, InBuffer.Length, 1411 | OutBuffer, OutBuffer.Length, ref bytesReturned, IntPtr.Zero); 1412 | if (bResult) 1413 | { 1414 | FileName = String.Format("DiagData-{0}.bin", ServiceName); 1415 | FilePath += "\\" + FileName; 1416 | 1417 | file = File.Create(FilePath); 1418 | file.Write(OutBuffer, 0, bytesReturned); 1419 | } 1420 | else 1421 | { 1422 | ErrString.Append("MarvellGetDiagDataIoctl: DeviceIoControl failed with error " + Marshal.GetLastWin32Error()); 1423 | bytesReturned = 0; 1424 | } 1425 | } 1426 | catch (Exception e) 1427 | { 1428 | ErrString.Append("MarvellGetDiagDataIoctl: Exception generated: " + e.Message); 1429 | } 1430 | finally 1431 | { 1432 | if (file != null) 1433 | { 1434 | file.Close(); 1435 | } 1436 | if (shwnd != null) 1437 | { 1438 | shwnd.Close(); 1439 | } 1440 | } 1441 | 1442 | return bytesReturned; 1443 | } 1444 | } 1445 | "@ 1446 | 1447 | try { 1448 | $NDIS_PnPDeviceID = (Get-NetAdapter -Name $NicName).PnPDeviceID 1449 | $NDIS_DeviceID = (Get-NetAdapter -Name $NicName).DeviceID 1450 | $NDIS_Service = (Get-PnpDeviceProperty -InstanceId "$NDIS_PnPDeviceID" -KeyName "DEVPKEY_Device_Service").Data 1451 | $VBD_DeviceID = (Get-PnpDeviceProperty -InstanceId "$NDIS_PnPDeviceID" -KeyName "DEVPKEY_Device_Parent").Data 1452 | $VBD_Service = (Get-PnpDeviceProperty -InstanceId "$VBD_DeviceID" -KeyName "DEVPKEY_Device_Service").Data 1453 | 1454 | $file = "$NicName-BusVerifierInfo.txt" 1455 | [String []] $cmds = "verifier /query", 1456 | "Get-PnpDeviceProperty -InstanceId '$VBD_DeviceID' | Select-Object KeyName, Data | Format-Table -AutoSize" 1457 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1458 | 1459 | $file = "$NicName-NicVerifierInfo.txt" 1460 | [String []] $cmds = "verifier /query", 1461 | "Get-PnpDeviceProperty -InstanceId '$NDIS_PnPDeviceID' | Select-Object KeyName, Data | Format-Table -Autosize" 1462 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1463 | 1464 | Add-Type -TypeDefinition $MarvellGetDiagDataClass -ErrorAction Stop 1465 | $r = New-Object -TypeName "MarvellGetDiagData" 1466 | $errorString = New-Object -TypeName "System.Text.StringBuilder" 1467 | 1468 | $output = $r.MarvellGetDiagDataIoctl($VBD_DeviceID, $OutDir, $VBD_Service, $errorString) 1469 | if ($output -le 0) { 1470 | $msg = $errorString.ToString() 1471 | ExecControlError -OutDir $OutDir -Message $msg 1472 | } 1473 | 1474 | $output = $r.MarvellGetDiagDataIoctl($NDIS_DeviceID, $OutDir, $NDIS_Service, $errorString) 1475 | if ($output -le 0) { 1476 | $msg = $errorString.ToString() 1477 | ExecControlError -OutDir $OutDir -Message $msg 1478 | } 1479 | } catch { 1480 | $msg = $($error[0] | Out-String) 1481 | ExecControlError -OutDir $OutDir -Message $msg 1482 | } finally { 1483 | Remove-Variable MarvellGetDiagDataClass -ErrorAction SilentlyContinue 1484 | } 1485 | } # Marvell Detail 1486 | 1487 | function IntelDetail { 1488 | [CmdletBinding()] 1489 | Param( 1490 | [parameter(Mandatory=$true)] [String] $NicName, 1491 | [parameter(Mandatory=$true)] [String] $OutDir 1492 | ) 1493 | 1494 | IntelReadETrackId -NicName $NicName -OutDir $OutDir 1495 | } # Intel Detail 1496 | 1497 | function IntelReadETrackId { 1498 | [CmdLetBinding()] 1499 | Param( 1500 | [parameter(Mandatory=$true)] [String] $NicName, 1501 | [parameter(Mandatory=$true)] [String] $OutDir 1502 | ) 1503 | 1504 | $file = "IntelETrackID.txt" 1505 | [String []] $cmds = "'ETrackID:', '{0:X}' -f (Get-CimInstance -Namespace 'root/wmi' -ClassName 'IntlLan_EetrackId').Where({`$_.InstanceName -eq (Get-NetAdapter -Name '$NicName').InterfaceDescription}).Id" 1506 | ExecCommandsAsync -OutDir $OutDir -File $file -Commands $cmds 1507 | } # IntelReadETrackId 1508 | 1509 | <# 1510 | .SYNOPSIS 1511 | Function stub for extension by IHVs Copy and rename it, 1512 | add your commands, and call it in NicVendor() below 1513 | #> 1514 | function MyVendorDetail { 1515 | [CmdletBinding()] 1516 | Param( 1517 | [parameter(Mandatory=$false)] [String] $NicName, 1518 | [parameter(Mandatory=$true)] [String] $OutDir 1519 | ) 1520 | 1521 | $dir = Join-Path -Path $OutDir -ChildPath "MyVendorDetail" 1522 | 1523 | # Try to keep the layout of this block of code 1524 | # Feel free to copy it or wrap it in other control structures 1525 | # See other functions in this file for examples 1526 | $file = "CommandOutput.txt" 1527 | [String []] $cmds = "Command 1", 1528 | "Command 2", 1529 | "Command 3", 1530 | "etc." 1531 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1532 | } # MyVendorDetail() 1533 | 1534 | function NicVendor { 1535 | [CmdletBinding()] 1536 | Param( 1537 | [parameter(Mandatory=$true)] [String] $NicName, 1538 | [parameter(Mandatory=$true)] [String] $OutDir 1539 | ) 1540 | 1541 | $dir = $OutDir 1542 | 1543 | $pciId = TryCmd {(Get-NetAdapterAdvancedProperty -Name $NicName -AllProperties -RegistryKeyword "ComponentID").RegistryValue} 1544 | switch -Wildcard($pciId) { 1545 | "CHT*BUS\chnet*" { 1546 | ChelsioDetail $NicName $dir 1547 | break 1548 | } 1549 | "PCI\VEN_15B3*" { 1550 | MellanoxDetail $NicName $dir 1551 | break 1552 | } 1553 | "*ConnectX-3*" { 1554 | MellanoxDetail $NicName $dir 1555 | break 1556 | } 1557 | "*EBDRV\L2ND*" { 1558 | MarvellDetail $NicName $dir 1559 | break 1560 | } 1561 | "PCI\VEN_8086*" { 1562 | IntelDetail $NicName $dir 1563 | break 1564 | } 1565 | # To extend refer to MyVendorDetail() above. 1566 | default { 1567 | } 1568 | } 1569 | } # NicVendor() 1570 | 1571 | function HostVNicWorker { 1572 | [CmdletBinding()] 1573 | Param( 1574 | [parameter(Mandatory=$false)] [String] $DeviceId, 1575 | [parameter(Mandatory=$true)] [String] $OutDir 1576 | ) 1577 | 1578 | # We need to get the actual name of the VM adapter as it can be different than that of the Get-NetAdapter output 1579 | # Also, the Get-VMNetworkAdapter cmdlet is the only one that can identify the adapter by DeviceID 1580 | [String] $vmNic = (Get-VMNetworkAdapter -ManagementOS | where {$_.DeviceId -eq "$DeviceId"}).Name 1581 | 1582 | $dir = $OutDir 1583 | 1584 | $file = "Get-VMNetworkAdapter.txt" 1585 | [String []] $cmds = "Get-VMNetworkAdapter -ManagementOS | where {`$_.DeviceId -eq ""$DeviceId""}", 1586 | "Get-VMNetworkAdapter -ManagementOS | where {`$_.DeviceId -eq ""$DeviceId""} | Format-List -Property *" 1587 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1588 | 1589 | $file = "Get-VMNetworkAdapterAcl.txt" 1590 | [String []] $cmds = "Get-VMNetworkAdapterAcl -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""}", 1591 | "Get-VMNetworkAdapterAcl -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""} | Format-List -Property *" 1592 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1593 | 1594 | $file = "Get-VMNetworkAdapterExtendedAcl.txt" 1595 | [String []] $cmds = "Get-VMNetworkAdapterExtendedAcl -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""}", 1596 | "Get-VMNetworkAdapterExtendedAcl -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""} | Format-List -Property *" 1597 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1598 | 1599 | $file = "Get-VMNetworkAdapterIsolation.txt" 1600 | [String []] $cmds = "Get-VMNetworkAdapterIsolation -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""}", 1601 | "Get-VMNetworkAdapterIsolation -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""} | Format-List -Property *" 1602 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1603 | 1604 | $file = "Get-VMNetworkAdapterRoutingDomainMapping.txt" 1605 | [String []] $cmds = "Get-VMNetworkAdapterRoutingDomainMapping -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""}", 1606 | "Get-VMNetworkAdapterRoutingDomainMapping -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""} | Format-List -Property *" 1607 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1608 | 1609 | $file = "Get-VMNetworkAdapterTeamMapping.txt" 1610 | [String []] $cmds = "Get-VMNetworkAdapterTeamMapping -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""}", 1611 | "Get-VMNetworkAdapterTeamMapping -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""} | Format-List -Property *" 1612 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1613 | 1614 | $file = "Get-VMNetworkAdapterVlan.txt" 1615 | [String []] $cmds = "Get-VMNetworkAdapterVlan -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""}", 1616 | "Get-VMNetworkAdapterVlan -ManagementOS | where {`$_.ParentAdapter.Name -contains ""$vmNic""} | Format-List -Property *" 1617 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1618 | } # HostVNicWorker() 1619 | 1620 | function HostVNicDetail { 1621 | [CmdletBinding()] 1622 | Param( 1623 | [parameter(Mandatory=$false)] [String] $VMSwitchId, 1624 | [parameter(Mandatory=$true)] [String] $OutDir 1625 | ) 1626 | 1627 | # Cache output 1628 | $allNetAdapters = Get-NetAdapter -IncludeHidden 1629 | 1630 | foreach ($hnic in TryCmd {Get-VMNetworkAdapter -ManagementOS} | where {$_.SwitchId -eq $VMSwitchId}) { 1631 | # Use device ID to find corresponding NetAdapter instance 1632 | $nic = $allNetAdapters | where {$_.DeviceID -eq $hnic.DeviceID} 1633 | 1634 | NetAdapterWorkerPrepare -NicName $nic.Name -Type "hNIC" -OutDir $OutDir 1635 | } 1636 | } # HostVNicDetail() 1637 | 1638 | function VMNetworkAdapterDetail { 1639 | [CmdletBinding()] 1640 | Param( 1641 | [parameter(Mandatory=$false)] [String] $VMName, 1642 | [parameter(Mandatory=$false)] [String] $VMNicName, 1643 | [parameter(Mandatory=$false)] [String] $VMNicId, 1644 | [parameter(Mandatory=$true)] [String] $OutDir 1645 | ) 1646 | 1647 | $name = $VMNicName 1648 | $id = $VMNicId 1649 | $title = "VMNic.$name.$id" 1650 | 1651 | $dir = Join-Path $OutDir $(ConvertTo-Filename $title) 1652 | $null = New-Item -ItemType directory -Path $dir 1653 | 1654 | # We must use Id to identity VMNics, because different VMNics 1655 | # can have the same MAC (none if VM is off), Name, VMName, and SwitchName. 1656 | [String] $vmNicObject = "`$(Get-VMNetworkAdapter -VMName ""$VMName"" -Name ""$VMNicName"" | where {`$_.Id -like ""*$id""})" 1657 | 1658 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $title" 1659 | $file = "Get-VMNetworkAdapter.txt" 1660 | [String []] $cmds = "$vmNicObject", 1661 | "$vmNicObject | Format-List -Property *" 1662 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1663 | 1664 | $file = "Get-VMNetworkAdapterAcl.txt" 1665 | [String []] $cmds = "Get-VMNetworkAdapterAcl -VMNetworkAdapter $vmNicObject", 1666 | "Get-VMNetworkAdapterAcl -VMNetworkAdapter $vmNicObject | Format-List -Property *" 1667 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1668 | 1669 | $file = "Get-VMNetworkAdapterExtendedAcl.txt" 1670 | [String []] $cmds = "Get-VMNetworkAdapterExtendedAcl -VMNetworkAdapter $vmNicObject", 1671 | "Get-VMNetworkAdapterExtendedAcl -VMNetworkAdapter $vmNicObject | Format-List -Property *" 1672 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1673 | 1674 | $file = "Get-VMNetworkAdapterFailoverConfiguration.txt" 1675 | [String []] $cmds = "Get-VMNetworkAdapterFailoverConfiguration -VMNetworkAdapter $vmNicObject", 1676 | "Get-VMNetworkAdapterFailoverConfiguration -VMNetworkAdapter $vmNicObject | Format-List -Property *" 1677 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1678 | 1679 | $file = "Get-VMNetworkAdapterIsolation.txt" 1680 | [String []] $cmds = "Get-VMNetworkAdapterIsolation -VMNetworkAdapter $vmNicObject", 1681 | "Get-VMNetworkAdapterIsolation -VMNetworkAdapter $vmNicObject | Format-List -Property *" 1682 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1683 | 1684 | $file = "Get-VMNetworkAdapterRoutingDomainMapping.txt" 1685 | [String []] $cmds = "Get-VMNetworkAdapterRoutingDomainMapping -VMNetworkAdapter $vmNicObject", 1686 | "Get-VMNetworkAdapterRoutingDomainMapping -VMNetworkAdapter $vmNicObject | Format-List -Property *" 1687 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1688 | 1689 | $file = "Get-VMNetworkAdapterTeamMapping.txt" 1690 | [String []] $cmds = "Get-VMNetworkAdapterTeamMapping -VMNetworkAdapter $vmNicObject", 1691 | "Get-VMNetworkAdapterTeamMapping -VMNetworkAdapter $vmNicObject | Format-List -Property *" 1692 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1693 | 1694 | $file = "Get-VMNetworkAdapterVlan.txt" 1695 | [String []] $cmds = "Get-VMNetworkAdapterVlan -VMNetworkAdapter $vmNicObject", 1696 | "Get-VMNetworkAdapterVlan -VMNetworkAdapter $vmNicObject | Format-List -Property *" 1697 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1698 | 1699 | $file = "Get-VMSwitchExtensionPortFeature.txt" 1700 | [String []] $cmds = "Get-VMSwitchExtensionPortFeature -VMNetworkAdapter $vmNicObject | Format-List -Property *" 1701 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1702 | 1703 | $file = "Get-VMSwitchExtensionPortData.txt" 1704 | [String []] $cmds = "Get-VMSwitchExtensionPortData -VMNetworkAdapter $vmNicObject | Format-List -Property *" 1705 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1706 | } # VMNetworkAdapterDetail() 1707 | 1708 | function VMWorker { 1709 | [CmdletBinding()] 1710 | Param( 1711 | [parameter(Mandatory=$false)] [String] $VMId, 1712 | [parameter(Mandatory=$true)] [String] $OutDir 1713 | ) 1714 | 1715 | $id = $VMId 1716 | $dir = $OutDir 1717 | 1718 | # Different VMs can have the same name 1719 | [String] $vmObject = "`$(Get-VM -Id $id)" 1720 | 1721 | $file = "Get-VM.txt" 1722 | [String []] $cmds = "$vmObject", 1723 | "$vmObject | Format-List -Property *" 1724 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1725 | 1726 | $file = "Get-VMBios.txt" 1727 | [String []] $cmds = "Get-VMBios -VM $vmObject", 1728 | "Get-VMBios -VM $vmObject | Format-List -Property *" 1729 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1730 | 1731 | $file = "Get-VMFirmware.txt" 1732 | [String []] $cmds = "Get-VMFirmware -VM $vmObject", 1733 | "Get-VMFirmware -VM $vmObject | Format-List -Property *" 1734 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1735 | 1736 | $file = "Get-VMProcessor.txt" 1737 | [String []] $cmds = "Get-VMProcessor -VM $vmObject", 1738 | "Get-VMProcessor -VM $vmObject | Format-List -Property *" 1739 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1740 | 1741 | $file = "Get-VMMemory.txt" 1742 | [String []] $cmds = "Get-VMMemory -VM $vmObject", 1743 | "Get-VMMemory -VM $vmObject | Format-List -Property *" 1744 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1745 | 1746 | $file = "Get-VMVideo.txt" 1747 | [String []] $cmds = "Get-VMVideo -VM $vmObject", 1748 | "Get-VMVideo -VM $vmObject | Format-List -Property *" 1749 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1750 | 1751 | $file = "Get-VMHardDiskDrive.txt" 1752 | [String []] $cmds = "Get-VMHardDiskDrive -VM $vmObject", 1753 | "Get-VMHardDiskDrive -VM $vmObject | Format-List -Property *" 1754 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1755 | 1756 | $file = "Get-VMComPort.txt" 1757 | [String []] $cmds = "Get-VMComPort -VM $vmObject", 1758 | "Get-VMComPort -VM $vmObject | Format-List -Property *" 1759 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1760 | 1761 | $file = "Get-VMSecurity.txt" 1762 | [String []] $cmds = "Get-VMSecurity -VM $vmObject", 1763 | "Get-VMSecurity -VM $vmObject | Format-List -Property *" 1764 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1765 | } # VMWorker() 1766 | 1767 | function VMNetworkAdapterPerVM { 1768 | [CmdletBinding()] 1769 | Param( 1770 | [parameter(Mandatory=$false)] [String] $VMSwitchId, 1771 | [parameter(Mandatory=$true)] [String] $OutDir 1772 | ) 1773 | 1774 | if (-not $SkipVm) { 1775 | [Int] $index = 1 1776 | foreach ($vm in TryCmd {Get-VM}) { 1777 | $vmName = $vm.Name 1778 | $vmId = $vm.VMId 1779 | $title = "VM.$index.$vmName" 1780 | $dir = Join-Path $OutDir $(ConvertTo-Filename $title) 1781 | 1782 | $vmQuery = $false 1783 | foreach ($vmNic in TryCmd {Get-VMNetworkAdapter -VM $vm} | where {$_.SwitchId -eq $VMSwitchId}) { 1784 | $vmNicId = ($vmNic.Id -split "\\")[1] # Same as AdapterId, but works if VM is off 1785 | if (-not $vmQuery) 1786 | { 1787 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $title" 1788 | New-Item -ItemType "Directory" -Path $dir | Out-Null 1789 | VMWorker -VMId $vmId -OutDir $dir 1790 | $vmQuery = $true 1791 | } 1792 | VMNetworkAdapterDetail -VMName $vmName -VMNicName $vmNic.Name -VMNicId $vmNicId -OutDir $dir 1793 | } 1794 | $index++ 1795 | } 1796 | } 1797 | } # VMNetworkAdapterPerVM() 1798 | 1799 | function VMSwitchWorker { 1800 | [CmdletBinding()] 1801 | Param( 1802 | [parameter(Mandatory=$false)] [String] $VMSwitchId, 1803 | [parameter(Mandatory=$true)] [String] $OutDir 1804 | ) 1805 | 1806 | $id = $VMSwitchId 1807 | $dir = $OutDir 1808 | 1809 | $vmSwitchObject = "`$(Get-VMSwitch -Id $id)" 1810 | $vmSwitchName = (Get-VMSwitch -Id $id).Name 1811 | 1812 | $file = "Get-VMSwitch.txt" 1813 | [String []] $cmds = "$vmSwitchObject", 1814 | "$vmSwitchObject | Format-List -Property *" 1815 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1816 | 1817 | $file = "Get-VMSwitchExtension.txt" 1818 | [String []] $cmds = "Get-VMSwitchExtension -VMSwitch $vmSwitchObject | Format-List -Property *" 1819 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1820 | 1821 | $file = "Get-VMSwitchExtensionSwitchData.txt" 1822 | [String []] $cmds = "Get-VMSwitchExtensionSwitchData -VMSwitch $vmSwitchObject | Format-List -Property *" 1823 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1824 | 1825 | $file = "Get-VMSwitchExtensionSwitchFeature.txt" 1826 | [String []] $cmds = "Get-VMSwitchExtensionSwitchFeature -VMSwitch $vmSwitchObject | Format-List -Property *" 1827 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1828 | 1829 | $file = "Get-VMSwitchTeam.txt" 1830 | [String []] $cmds = "Get-VMSwitchTeam -VMSwitch $vmSwitchObject | Format-List -Property *" 1831 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1832 | 1833 | $file = "Get-VMNetworkAdapterTeamMapping.txt" 1834 | [String []] $cmds = "Get-VMNetworkAdapterTeamMapping -ManagementOS -SwitchName '$vmSwitchName' | Format-List -Property *" 1835 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1836 | } # VMSwitchWorker() 1837 | 1838 | function VfpExtensionDetail { 1839 | [CmdletBinding()] 1840 | Param( 1841 | [parameter(Mandatory=$false)] [String] $VMSwitchId, 1842 | [parameter(Mandatory=$true)] [String] $OutDir 1843 | ) 1844 | 1845 | #FIXME: Find a non-vSwitch CMDLET mechanism to dump the VFP settings 1846 | # Necessary for HNS scenarios where vSwitch CMDLETs are not available 1847 | $id = $VMSwitchId 1848 | $vfpExtension = TryCmd {Get-VMSwitch -Id $id | Get-VMSwitchExtension} | where {$_.Name -like "Microsoft Azure VFP Switch Extension"} 1849 | 1850 | if ($vfpExtension.Enabled -ne "True") { 1851 | return 1852 | } 1853 | 1854 | $dir = (Join-Path -Path $OutDir -ChildPath "VFP") 1855 | New-Item -ItemType directory -Path $dir | Out-Null 1856 | 1857 | $file = "VfpCtrl.help.txt" 1858 | [String []] $cmds = "vfpctrl.exe /h" 1859 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1860 | 1861 | $file = "Get-CimInstance.CIM_DataFile.vfpext.txt" 1862 | $vfpExtPath = ((Join-Path $env:SystemRoot "System32\drivers\vfpext.sys") -replace "\\","\\") 1863 | [String []] $cmds = "Get-CimInstance -ClassName ""CIM_DataFile"" -Filter ""Name='$vfpExtPath'""" 1864 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1865 | 1866 | $file = "VfpCtrl.VmSwitchPort.txt" 1867 | [string []] $cmds = "vfpctrl.exe /list-vmswitch-port" 1868 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1869 | 1870 | $currSwitch = Get-CimInstance -Filter "Name='$id'" -ClassName "Msvm_VirtualEthernetSwitch" -Namespace "Root\Virtualization\v2" 1871 | $ports = Get-CimAssociatedInstance -InputObject $currSwitch -ResultClassName "Msvm_EthernetSwitchPort" 1872 | if ($ports) { 1873 | foreach ($portGuid in $ports.Name) { 1874 | $file = "VfpCtrl.PortGuid.$portGuid.txt" 1875 | [String []] $cmds = "vfpctrl.exe /get-flow-stats /port $portGuid", 1876 | "vfpctrl.exe /get-port-state /port $portGuid", 1877 | "vfpctrl.exe /get-port-flow-settings /port $portGuid", 1878 | "vfpctrl.exe /get-port-flow-stats /port $portGuid", 1879 | "vfpctrl.exe /list-mapping /port $portGuid", 1880 | "vfpctrl.exe /list-nat-range /port $portGuid", 1881 | "vfpctrl.exe /list-rule /port $portGuid", 1882 | "vfpctrl.exe /list-space /port $portGuid", 1883 | "vfpctrl.exe /list-unified-flow /port $portGuid" 1884 | 1885 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1886 | } 1887 | } 1888 | } # VfpExtensionDetail() 1889 | 1890 | function VMSwitchDetail { 1891 | [CmdletBinding()] 1892 | Param( 1893 | [parameter(Mandatory=$true)] [String] $OutDir 1894 | ) 1895 | 1896 | # Acquire switch properties/settings via CMD tools 1897 | $dir = (Join-Path -Path $OutDir -ChildPath "VMSwitch.Detail") 1898 | New-Item -ItemType directory -Path $dir | Out-Null 1899 | 1900 | $file = "VmspRegistry.txt" 1901 | [String []] $cmds = "Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services\vmsmp -Recurse" 1902 | ExecCommands -OutDir $dir -File $file -Commands $cmds 1903 | 1904 | if (-not $SkipNvspInfo ){ 1905 | $file = "NvspInfo.txt" 1906 | [String []] $cmds = "nvspinfo -a -i -h -D -p -d -m -q " 1907 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1908 | 1909 | $file = "NvspInfo_bindings.txt" 1910 | [String []] $cmds = "nvspinfo -a -i -h -D -p -d -m -q -b " 1911 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1912 | 1913 | $file = "NvspInfo_ExecMon.txt" 1914 | [String []] $cmds = "nvspinfo -X --count --sort max ", 1915 | "nvspinfo -X --count IOCTL --sort max", 1916 | "nvspinfo -X --count OID --sort max", 1917 | "nvspinfo -X --count WORKITEM --sort max", 1918 | "nvspinfo -X --count RNDIS --sort max" 1919 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1920 | 1921 | $file = "NmScrub.txt" 1922 | [String []] $cmds = "nmscrub -a -n -t " 1923 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1924 | } 1925 | 1926 | # Acquire per vSwitch instance info/mappings 1927 | [Int] $index = 1 1928 | foreach ($vmSwitch in TryCmd {Get-VMSwitch}) { 1929 | $name = $vmSwitch.Name 1930 | $type = $vmSwitch.SwitchType 1931 | $id = $vmSwitch.Id 1932 | $title = "VMSwitch.$index.$type.$name" 1933 | 1934 | $dir = Join-Path $OutDir $(ConvertTo-Filename $title) 1935 | New-Item -ItemType directory -Path $dir | Out-Null 1936 | 1937 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $title" 1938 | VfpExtensionDetail -VMSwitchId $id -OutDir $dir 1939 | VMSwitchWorker -VMSwitchId $id -OutDir $dir 1940 | ProtocolNicDetail -VMSwitchId $id -OutDir $dir 1941 | HostVNicDetail -VMSwitchId $id -OutDir $dir 1942 | VMNetworkAdapterPerVM -VMSwitchId $id -OutDir $dir 1943 | 1944 | $index++ 1945 | } 1946 | } # VMSwitchDetail() 1947 | 1948 | function NetworkSummary { 1949 | [CmdletBinding()] 1950 | Param( 1951 | [parameter(Mandatory=$true)] [String] $OutDir 1952 | ) 1953 | 1954 | $dir = $OutDir 1955 | 1956 | $file = "Get-NetOffloadGlobalSetting.txt" 1957 | [String []] $cmds = "Get-NetOffloadGlobalSetting", 1958 | "Get-NetOffloadGlobalSetting | Format-List -Property *" 1959 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1960 | 1961 | $file = "Get-VMSwitch.txt" 1962 | [String []] $cmds = "Get-VMSwitch | Sort-Object Name | Format-Table -AutoSize", 1963 | "Get-VMSwitch | Sort-Object Name | Format-Table -Property * -AutoSize" 1964 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1965 | 1966 | $file = "Get-VMNetworkAdapter.txt" 1967 | [String []] $cmds = "Get-VmNetworkAdapter -All | Sort-Object IsManagementOS | Sort-Object SwitchName | Format-Table -AutoSize", 1968 | "Get-VmNetworkAdapter -All | Sort-Object IsManagementOS | Sort-Object SwitchName | Format-Table -Property * -AutoSize" 1969 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1970 | 1971 | $file = "Get-NetAdapter.txt" 1972 | [String []] $cmds = "Get-NetAdapter -IncludeHidden | Sort-Object InterfaceDescription | Format-Table -AutoSize", 1973 | "Get-NetAdapter -IncludeHidden | Sort-Object InterfaceDescription | Format-Table -Property * -AutoSize" 1974 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1975 | 1976 | $file = "Get-NetAdapterStatistics.txt" 1977 | [String []] $cmds = "Get-NetAdapterStatistics -IncludeHidden | Sort-Object InterfaceDescription | Format-Table -Autosize", 1978 | "Get-NetAdapterStatistics -IncludeHidden | Sort-Object InterfaceDescription | Format-Table -Property * -Autosize" 1979 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1980 | 1981 | $file = "Get-NetLbfoTeam.txt" 1982 | [String []] $cmds = "Get-NetLbfoTeam | Sort-Object InterfaceDescription | Format-Table -Autosize", 1983 | "Get-NetLbfoTeam | Sort-Object InterfaceDescription | Format-Table -Property * -AutoSize" 1984 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1985 | 1986 | $file = "Get-NetIpAddress.txt" 1987 | [String []] $cmds = "Get-NetIpAddress | Format-Table -Autosize", 1988 | "Get-NetIpAddress | Format-Table -Property * -AutoSize" 1989 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1990 | 1991 | $file = "_ipconfig.txt" 1992 | [String []] $cmds = "ipconfig", 1993 | "ipconfig /allcompartments /all" 1994 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1995 | 1996 | $file = "_arp.txt" 1997 | [String []] $cmds = "arp -a" 1998 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 1999 | 2000 | $file = "_netstat.txt" 2001 | [String []] $cmds = "netstat -nasert", 2002 | "netstat -an", 2003 | "netstat -xan | ? {`$_ -match ""445""}" 2004 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2005 | 2006 | $file = "_nmbind.txt" 2007 | [String []] $cmds = "nmbind" 2008 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2009 | 2010 | $file = "_advfirewall.txt" 2011 | [String []] $cmds = "netsh advfirewall show allprofiles" 2012 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2013 | 2014 | $file = "_netcfg.txt" 2015 | [String []] $cmds = "netcfg -s n", 2016 | "netcfg -m -v" 2017 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2018 | } # NetworkSummary() 2019 | 2020 | function PktmonDetail { 2021 | [CmdletBinding()] 2022 | Param( 2023 | [parameter(Mandatory=$true)] [String] $OutDir 2024 | ) 2025 | 2026 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $($MyInvocation.MyCommand.Name)" 2027 | 2028 | $dir = (Join-Path -Path $OutDir -ChildPath "Pktmon") 2029 | New-Item -ItemType directory -Path $dir | Out-Null 2030 | 2031 | $file = "pktmon.status.txt" 2032 | [String []] $cmds = "pktmon status", 2033 | "pktmon stop" # End any pre-existing session 2034 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2035 | 2036 | $file = "pktmon.filter.txt" 2037 | [String []] $cmds = "pktmon filter list" 2038 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2039 | 2040 | $file = "pktmon.list.txt" 2041 | [String []] $cmds = "pktmon list", 2042 | "pktmon list --all", 2043 | "pktmon list --all --include-hidden" 2044 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2045 | 2046 | # Reset state and collect a small snapshot of traffic counters. 2047 | $null = pktmon unload 2048 | 2049 | $file = "pktmon.counters.txt" 2050 | [String []] $cmds = "pktmon start --capture --counters-only --comp all", 2051 | "Start-Sleep 1", 2052 | "pktmon counters --include-hidden --zero --drop-reason" 2053 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2054 | 2055 | $null = pktmon unload 2056 | } # PktmonDetail() 2057 | 2058 | function SMBDetail { 2059 | [CmdletBinding()] 2060 | Param( 2061 | [parameter(Mandatory=$true)] [String] $OutDir 2062 | ) 2063 | 2064 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $($MyInvocation.MyCommand.Name)" 2065 | 2066 | $dir = (Join-Path -Path $OutDir -ChildPath "SMB") 2067 | New-Item -ItemType directory -Path $dir | Out-Null 2068 | 2069 | $file = "Get-SmbConnection.txt" 2070 | [String []] $cmds = "Get-SmbConnection" 2071 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2072 | 2073 | $file = "Get-SmbMapping.txt" 2074 | [String []] $cmds = "Get-SmbMapping" 2075 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2076 | 2077 | $file = "Get-SmbOpenFile.txt" 2078 | [String []] $cmds = "Get-SmbOpenFile" 2079 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2080 | 2081 | $file = "Get-SmbSession.txt" 2082 | [String []] $cmds = "Get-SmbSession" 2083 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2084 | 2085 | $file = "Get-SmbShare.txt" 2086 | [String []] $cmds = "Get-SmbShare" 2087 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2088 | 2089 | $file = "Get-SmbClientNetworkInterface.txt" 2090 | [String []] $cmds = "Get-SmbClientNetworkInterface | Sort-Object FriendlyName | Format-Table -AutoSize", 2091 | "Get-SmbClientNetworkInterface | Format-List -Property *" 2092 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2093 | 2094 | $file = "Get-SmbServerNetworkInterface.txt" 2095 | [String []] $cmds = "Get-SmbServerNetworkInterface | Sort-Object FriendlyName | Format-Table -AutoSize", 2096 | "Get-SmbServerNetworkInterface | Format-List -Property *" 2097 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2098 | 2099 | $file = "Get-SmbClientConfiguration.txt" 2100 | [String []] $cmds = "Get-SmbClientConfiguration" 2101 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2102 | 2103 | $file = "Get-SmbServerConfiguration.txt" 2104 | [String []] $cmds = "Get-SmbServerConfiguration" 2105 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2106 | 2107 | $file = "Get-SmbMultichannelConnection.txt" 2108 | [String []] $cmds = "Get-SmbMultichannelConnection | Sort-Object Name | Format-Table -AutoSize", 2109 | "Get-SmbMultichannelConnection -IncludeNotSelected | Format-List -Property *", 2110 | "Get-SmbMultichannelConnection -SmbInstance CSV -IncludeNotSelected | Format-List -Property *", 2111 | "Get-SmbMultichannelConnection -SmbInstance SBL -IncludeNotSelected | Format-List -Property *" 2112 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2113 | 2114 | $file = "Get-SmbMultichannelConstraint.txt" 2115 | [String []] $cmds = "Get-SmbMultichannelConstraint" 2116 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2117 | 2118 | $file = "Get-SmbBandwidthLimit.txt" 2119 | [String []] $cmds = "Get-SmbBandwidthLimit" 2120 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2121 | 2122 | if (-not $SkipSMBEvents ){ 2123 | $file = "Smb-WindowsEvents.txt" 2124 | [String []] $cmds = "Get-WinEvent -ListLog ""*SMB*"" | Format-List -Property *", 2125 | "Get-WinEvent -FilterHashtable @{LogName=""Microsoft-Windows-SMB*""; ProviderName=""Microsoft-Windows-SMB*""} | where {`$_.Message -like ""*RDMA*""} | Format-List -Property *" 2126 | 2127 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2128 | } 2129 | } # SMBDetail() 2130 | 2131 | function NetSetupDetail { 2132 | [CmdletBinding()] 2133 | Param( 2134 | [parameter(Mandatory=$true)] [String] $OutDir 2135 | ) 2136 | 2137 | $dir = (Join-Path -Path $OutDir -ChildPath "NetSetup") 2138 | New-Item -ItemType directory -Path $dir | Out-Null 2139 | 2140 | $file = "NetSetup.txt" 2141 | [String []] $paths = "$env:SystemRoot\System32\NetSetupMig.log", 2142 | "$env:SystemRoot\Panther\setupact.log", 2143 | "$env:SystemRoot\INF\setupapi.*", 2144 | "$env:SystemRoot\logs\NetSetup" 2145 | ExecCopyItemsAsync -OutDir $dir -File $file -Paths $paths -Destination $dir 2146 | } # NetSetupDetail() 2147 | 2148 | function HNSDetail { 2149 | [CmdletBinding()] 2150 | Param( 2151 | [parameter(Mandatory=$true)] [String] $OutDir 2152 | ) 2153 | 2154 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $($MyInvocation.MyCommand.Name)" 2155 | 2156 | try { 2157 | $null = Get-Service "hns" -ErrorAction Stop 2158 | } catch { 2159 | Write-Host "$($MyInvocation.MyCommand.Name): hns service not found, skipping." 2160 | return 2161 | } 2162 | 2163 | $dir = (Join-Path -Path $OutDir -ChildPath "HNS") 2164 | New-Item -ItemType Directory -Path $dir | Out-Null 2165 | 2166 | # Data collected before stop -> start must be collected synchronously 2167 | 2168 | $file = "HNSRegistry-1.txt" 2169 | [String []] $cmds = "Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services\hns -Recurse", 2170 | "Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services\vmsmp -Recurse" 2171 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2172 | 2173 | $file = "Get-HNSNetwork-1.txt" 2174 | [String []] $cmds = "Get-HNSNetwork | ConvertTo-Json -Depth 10" 2175 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2176 | 2177 | $file = "Get-HNSEndpoint-1.txt" 2178 | [String []] $cmds = "Get-HNSEndpoint | ConvertTo-Json -Depth 10" 2179 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2180 | 2181 | # HNS service stop -> start occurs after capturing the current HNS state info. 2182 | $hnsRunning = (Get-Service hns).Status -eq "Running" 2183 | try { 2184 | if ($hnsRunning) { 2185 | # Force stop to avoid command line prompt 2186 | net stop hns /y *> $null 2187 | } 2188 | 2189 | $file = "HNSData.txt" 2190 | [String []] $cmds = "Copy-Item -Path ""$env:ProgramData\Microsoft\Windows\HNS\HNS.data"" -Destination $dir -Verbose 4>&1" 2191 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2192 | } finally { 2193 | if ($hnsRunning) { 2194 | net start hns *> $null 2195 | } 2196 | } 2197 | 2198 | # Acquire all settings again after stop -> start services 2199 | # From now on we can collect data asynchronously. 2200 | $file = "HNSRegistry-2.txt" 2201 | [String []] $cmds = "Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services\hns -Recurse", 2202 | "Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services\vmsmp -Recurse" 2203 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2204 | 2205 | $file = "Get-HNSNetwork-2.txt" 2206 | [String []] $cmds = "Get-HNSNetwork | ConvertTo-Json -Depth 10" 2207 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2208 | 2209 | $file = "Get-HNSEndpoint-2.txt" 2210 | [String []] $cmds = "Get-HNSEndpoint | ConvertTo-Json -Depth 10" 2211 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2212 | 2213 | $file = "HNSDiag_all.txt" 2214 | [String []] $cmds = "HNSDiag list all" 2215 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2216 | 2217 | $file = "HNSDiag_all_d.txt" 2218 | [String []] $cmds = "HNSDiag list all -d" 2219 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2220 | 2221 | $file = "HNSDiag_all_df.txt" 2222 | [String []] $cmds = "HNSDiag list all -df" 2223 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2224 | 2225 | $file = "HNSDiag_all_dfl.txt" 2226 | [String []] $cmds = "HNSDiag list all -dfl" 2227 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2228 | 2229 | #netsh trace start scenario=Virtualization provider=Microsoft-Windows-tcpip provider=Microsoft-Windows-winnat capture=yes captureMultilayer=yes capturetype=both report=disabled tracefile=$dir\server.etl overwrite=yes 2230 | #Start-Sleep 120 2231 | #netsh trace stop 2232 | } # HNSDetail() 2233 | 2234 | function QosDetail { 2235 | [CmdletBinding()] 2236 | Param( 2237 | [parameter(Mandatory=$true)] [String] $OutDir 2238 | ) 2239 | 2240 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $($MyInvocation.MyCommand.Name)" 2241 | 2242 | $dir = (Join-Path -Path $OutDir -ChildPath "NetQoS") 2243 | New-Item -ItemType directory -Path $dir | Out-Null 2244 | 2245 | $file = "Get-NetAdapterQos.txt" 2246 | [String []] $cmds = "Get-NetAdapterQos", 2247 | "Get-NetAdapterQos -IncludeHidden", 2248 | "Get-NetAdapterQos -IncludeHidden | Format-List -Property *" 2249 | ExecCommands -OutDir $dir -File $file -Commands $cmds # Get-NetAdapterQos has severe concurrency issues 2250 | 2251 | $file = "Get-NetQosDcbxSetting.txt" 2252 | [String []] $cmds = "Get-NetQosDcbxSetting", 2253 | "Get-NetQosDcbxSetting | Format-List -Property *", 2254 | "Get-NetQosDcbxSetting | Format-Table -Property * -AutoSize" 2255 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2256 | 2257 | $file = "Get-NetQosFlowControl.txt" 2258 | [String []] $cmds = "Get-NetQosFlowControl", 2259 | "Get-NetQosFlowControl | Format-List -Property *", 2260 | "Get-NetQosFlowControl | Format-Table -Property * -AutoSize" 2261 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2262 | 2263 | $file = "Get-NetQosPolicy.txt" 2264 | [String []] $cmds = "Get-NetQosPolicy", 2265 | "Get-NetQosPolicy | Format-List -Property *", 2266 | "Get-NetQosPolicy | Format-Table -Property * -AutoSize" 2267 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2268 | 2269 | $file = "Get-NetQosTrafficClass.txt" 2270 | [String []] $cmds = "Get-NetQosTrafficClass", 2271 | "Get-NetQosTrafficClass | Format-List -Property *", 2272 | "Get-NetQosTrafficClass | Format-Table -Property * -AutoSize" 2273 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2274 | } # QosDetail() 2275 | 2276 | function ATCDetail { 2277 | [CmdletBinding()] 2278 | param ( 2279 | [parameter(Mandatory=$true)] [String] $OutDir 2280 | ) 2281 | 2282 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $($MyInvocation.MyCommand.Name)" 2283 | 2284 | $intentCmd = Get-Command "Get-NetIntent" -ErrorAction "SilentlyContinue" 2285 | $clusterCmd = Get-Command "Get-Cluster" -ErrorAction "SilentlyContinue" 2286 | if (-not ($intentCmd -or $clusterCmd)) { 2287 | return 2288 | } 2289 | 2290 | $dir = (Join-Path -Path $OutDir -ChildPath "ATC") 2291 | New-Item -ItemType directory -Path $dir | Out-Null 2292 | 2293 | # Local Intents 2294 | if ($intentCmd) { 2295 | $file = "Get-NetIntent_Standalone.txt" 2296 | [String []] $cmds = "Get-NetIntent" 2297 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2298 | 2299 | $file = "Get-NetIntentStatus_Standalone.txt" 2300 | [String []] $cmds = "Get-NetIntentStatus" 2301 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2302 | 2303 | $file = "Get-NetIntentAllGoalStates_Standalone.txt" 2304 | [String []] $cmds = "Get-NetIntentAllGoalStates | ConvertTo-Json -Depth 10" 2305 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2306 | } 2307 | 2308 | # Cluster Intents 2309 | if ($clusterCmd) { 2310 | $cluster = TryCmd { Get-Cluster } 2311 | $file = "Get-NetIntent_Cluster.txt" 2312 | [String []] $cmds = "Get-NetIntent -ClusterName $($cluster.Name)" 2313 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2314 | 2315 | $file = "Get-NetIntentStatus_Cluster.txt" 2316 | [String []] $cmds = "Get-NetIntentStatus -ClusterName $($cluster.Name)" 2317 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2318 | 2319 | $file = "Get-NetIntentAllGoalStates_Cluster.txt" 2320 | [String []] $cmds = "Get-NetIntentAllGoalStates -ClusterName $($cluster.Name) | ConvertTo-Json -Depth 10" 2321 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2322 | } 2323 | } # ATCDetail () 2324 | 2325 | function ServicesDrivers { 2326 | [CmdletBinding()] 2327 | Param( 2328 | [parameter(Mandatory=$true)] [String] $OutDir 2329 | ) 2330 | 2331 | $dir = (Join-Path -Path $OutDir -ChildPath "ServicesDrivers") 2332 | New-Item -ItemType Directory -Path $dir | Out-Null 2333 | 2334 | $file = "sc.txt" 2335 | [String []] $cmds = "sc.exe queryex vmsp", 2336 | "sc.exe queryex vmsproxy", 2337 | "sc.exe queryex PktMon" 2338 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2339 | 2340 | $file = "Get-Service.txt" 2341 | [String []] $cmds = "Get-Service ""*"" | Sort-Object Name | Format-Table -AutoSize", 2342 | "Get-Service ""*"" | Sort-Object Name | Format-Table -Property * -AutoSize" 2343 | ExecCommands -OutDir $dir -File $file -Commands $cmds # Get-Service has concurrency issues 2344 | 2345 | if (-not $SkipOnline) { 2346 | $file = "Get-WindowsDriver.txt" 2347 | [String []] $cmds = "Get-WindowsDriver -Online -All" 2348 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2349 | } 2350 | if (-not $SkipOnline) { 2351 | $file = "Get-WindowsEdition.txt" 2352 | [String []] $cmds = "Get-WindowsEdition -Online" 2353 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2354 | } 2355 | $file = "Get-HotFix.txt" 2356 | [String []] $cmds = "Get-Hotfix | Sort-Object InstalledOn | Format-Table -AutoSize", 2357 | "Get-Hotfix | Sort-Object InstalledOn | Format-Table -Property * -AutoSize" 2358 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2359 | 2360 | $file = "Get-PnpDevice.txt" 2361 | [String []] $cmds = "Get-PnpDevice | Sort-Object Class, FriendlyName, InstanceId | Format-Table -AutoSize", 2362 | "Get-PnpDevice | Sort-Object Class, FriendlyName, InstanceId | Format-List -Property *" 2363 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2364 | 2365 | $file = "Get-CimInstance.Win32_PnPSignedDriver.txt" 2366 | [String []] $cmds = "Get-CimInstance Win32_PnPSignedDriver | Select-Object DeviceName, DeviceId, DriverVersion | Format-Table -AutoSize", 2367 | "Get-CimInstance Win32_PnPSignedDriver | Format-List -Property *" 2368 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2369 | 2370 | if (-not $SkipOnline) { 2371 | $file = "dism.txt" 2372 | [String []] $cmds = "dism /online /get-features" 2373 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2374 | } 2375 | } # ServicesDrivers() 2376 | 2377 | function VMHostDetail { 2378 | [CmdletBinding()] 2379 | Param( 2380 | [parameter(Mandatory=$true)] [String] $OutDir 2381 | ) 2382 | 2383 | $dir = (Join-Path -Path $OutDir -ChildPath "VMHost") 2384 | New-Item -ItemType Directory -Path $dir | Out-Null 2385 | 2386 | $file = "Get-VMHostSupportedVersion.txt" 2387 | [String []] $cmds = "Get-VMHostSupportedVersion | Format-Table -AutoSize", 2388 | "Get-VMHostSupportedVersion | Format-List -Property *" 2389 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2390 | 2391 | $file = "Get-VMHostNumaNode.txt" 2392 | [String []] $cmds = "Get-VMHostNumaNode" 2393 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2394 | 2395 | $file = "Get-VMHostNumaNodeStatus.txt" 2396 | [String []] $cmds = "Get-VMHostNumaNodeStatus" 2397 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2398 | 2399 | $file = "Get-VMSystemSwitchExtension.txt" 2400 | [String []] $cmds = "Get-VMSystemSwitchExtension | Format-List -Property *" 2401 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2402 | 2403 | $file = "Get-VMSystemSwitchExtensionSwitchFeature.txt" 2404 | [String []] $cmds = "Get-VMSystemSwitchExtensionSwitchFeature | Format-List -Property *" 2405 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2406 | 2407 | $file = "Get-VMSystemSwitchExtensionPortFeature.txt" 2408 | [String []] $cmds = "Get-VMSystemSwitchExtensionPortFeature | Format-List -Property *" 2409 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2410 | } # VMHostDetail() 2411 | 2412 | function NetshDetail { 2413 | [CmdletBinding()] 2414 | Param( 2415 | [parameter(Mandatory=$true)] [String] $OutDir, 2416 | [parameter(Mandatory=$true)] [Bool] $SkipNetshTrace 2417 | ) 2418 | 2419 | $dir = (Join-Path -Path $OutDir -ChildPath "Netsh") 2420 | New-Item -ItemType directory -Path $dir | Out-Null 2421 | 2422 | $wpp_vswitch = "{1F387CBC-6818-4530-9DB6-5F1058CD7E86}" 2423 | $wpp_ndis = "{DD7A21E6-A651-46D4-B7C2-66543067B869}" 2424 | $etw_tcpip = "{2F07E2EE-15DB-40F1-90EF-9D7BA282188A}" 2425 | $etw_quic = "{ff15e657-4f26-570e-88ab-0796b258d11c}" 2426 | 2427 | # The sequence below triggers the ETW providers to dump their 2428 | # internal traces when the session starts. Thus allowing for 2429 | # capturing a snapshot of their logs/traces. 2430 | # 2431 | # NOTE: This does not cover IFR (in-memory) traces. More work needed to address said traces. 2432 | $file = "NetRundown.txt" 2433 | [String []] $cmds = "New-NetEventSession NetRundown -CaptureMode SaveToFile -LocalFilePath $dir\NetRundown.etl", 2434 | "Add-NetEventProvider ""$wpp_vswitch"" -SessionName NetRundown -Level 1 -MatchAnyKeyword 0x10000", 2435 | "Add-NetEventProvider ""$wpp_ndis"" -SessionName NetRundown -Level 1 -MatchAnyKeyword 0x2", 2436 | "Add-NetEventProvider ""$etw_tcpip"" -SessionName NetRundown -Level 4", 2437 | "Add-NetEventProvider ""$etw_quic"" -SessionName NetRundown -Level 5 -MatchAnyKeyword 0x80000000", 2438 | "Start-NetEventSession NetRundown", 2439 | "Stop-NetEventSession NetRundown", 2440 | "Remove-NetEventSession NetRundown" 2441 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2442 | 2443 | # The ETL file can be converted to text using the following command: 2444 | # netsh trace convert NetRundown.etl tmfpath=\amd64fre\symbols.pri\TraceFormat 2445 | 2446 | $file = "NetshDump.txt" 2447 | [String []] $cmds = "netsh dump" 2448 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2449 | 2450 | $file = "NetshStatistics.txt" 2451 | [String []] $cmds = "netsh interface ipv4 show icmpstats", 2452 | "netsh interface ipv4 show ipstats", 2453 | "netsh interface ipv4 show tcpstats", 2454 | "netsh interface ipv4 show udpstats", 2455 | "netsh interface ipv4 show subinterfaces level=verbose", 2456 | "netsh interface fl48 show virtualinterfaces level=verbose", 2457 | "netsh interface ipv6 show ipstats", 2458 | "netsh interface ipv6 show tcpstats", 2459 | "netsh interface ipv6 show udpstats", 2460 | "netsh interface ipv6 show subinterfaces level=verbose", 2461 | "netsh interface fl68 show virtualinterfaces level=verbose" 2462 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2463 | 2464 | $file = "NetshTrace.txt" 2465 | [String []] $cmds = "netsh -?", 2466 | "netsh trace show scenarios", 2467 | "netsh trace show providers" 2468 | if (-not $SkipNetshTrace) { 2469 | $cmds += "netsh trace diagnose scenario=NetworkSnapshot mode=Telemetry saveSessionTrace=yes report=yes ReportFile=$dir\Snapshot.cab" 2470 | } 2471 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2472 | } # NetshDetail() 2473 | 2474 | function OneX { 2475 | [CmdletBinding()] 2476 | Param( 2477 | [parameter(Mandatory=$true)] [String] $OutDir 2478 | ) 2479 | 2480 | Write-Progress -Activity $Global:QueueActivity -Status "Processing $($MyInvocation.MyCommand.Name)" 2481 | 2482 | $dir = (Join-Path -Path $OutDir -ChildPath "802.1X") 2483 | New-Item -ItemType directory -Path $dir | Out-Null 2484 | 2485 | $file = "OneX.txt" 2486 | [String []] $cmds = "netsh lan show interface", 2487 | "netsh lan show profile" 2488 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2489 | } # OneX 2490 | 2491 | function CounterDetail { 2492 | [CmdletBinding()] 2493 | Param( 2494 | [parameter(Mandatory=$true)] [String] $OutDir 2495 | ) 2496 | 2497 | $dir = (Join-Path -Path $OutDir -ChildPath "Counters") 2498 | New-Item -ItemType directory -Path $dir | Out-Null 2499 | 2500 | $file = "CounterSetName.txt" 2501 | [String []] $cmds = "typeperf -q | foreach {(`$_ -split ""\\"")[1]} | Sort-Object -Unique" 2502 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2503 | 2504 | $file = "CounterSetName.Paths.txt" 2505 | [String []] $cmds = "typeperf -q" 2506 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2507 | 2508 | $file = "CounterSetName.PathsWithInstances.txt" 2509 | [String []] $cmds = "typeperf -qx" 2510 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2511 | 2512 | # Get paths for counters of interest 2513 | $file = "CounterDetail.InstancesToQuery.txt" 2514 | $in = Join-Path $dir $file 2515 | 2516 | $pathFilters = @("\Hyper-V*", "\ICMP*", "*Intel*", "*Cavium*", "\IP*", "*Mellanox*", "\Network*", "\Physical Network*", "\RDMA*", "\SMB*", "\TCP*", "\UDP*","\VFP*", "\WFP*", "*WinNAT*") 2517 | $instancesToQuery = typeperf -qx | where { 2518 | $instance = $_ 2519 | $pathFilters | foreach { 2520 | if ($instance -like $_) { 2521 | return $true 2522 | } 2523 | } 2524 | return $false 2525 | } 2526 | $instancesToQuery | Out-File -FilePath $in -Encoding "default" -Width $columns 2527 | 2528 | $file = "CounterDetail.csv" 2529 | $out = Join-Path $dir $file 2530 | [String []] $cmds = "typeperf -cf $in -sc 5 -si 1 -f CSV -o $out > `$null" 2531 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2532 | 2533 | } # CounterDetail() 2534 | 2535 | function SystemLogs { 2536 | [CmdletBinding()] 2537 | Param( 2538 | [parameter(Mandatory=$true)] [String] $OutDir 2539 | ) 2540 | 2541 | if (-not $SkipLogs) { 2542 | $dir = $OutDir 2543 | 2544 | $file = "WinEVT.txt" 2545 | [String []] $paths = "$env:SystemRoot\System32\winevt" 2546 | ExecCopyItemsAsync -OutDir $dir -File $file -Paths $paths -Destination $dir 2547 | 2548 | $file = "WER.txt" 2549 | [String []] $paths = "$env:ProgramData\Microsoft\Windows\WER" 2550 | ExecCopyItemsAsync -OutDir $dir -File $file -Paths $paths -Destination $dir 2551 | } else { 2552 | $dir = "$OutDir\winevt\Logs" 2553 | 2554 | $file = "ATCEVT.txt" 2555 | [String []] $paths = "$env:SystemRoot\System32\winevt\logs\Microsoft-Windows-Networking-NetworkAtc%4Operational.evtx", 2556 | "$env:SystemRoot\System32\winevt\logs\Microsoft-Windows-Networking-NetworkAtc%4Admin.evtx" 2557 | ExecCopyItemsAsync -OutDir $dir -File $file -Paths $paths -Destination $dir 2558 | } 2559 | } # SystemLogs() 2560 | 2561 | function Environment { 2562 | [CmdletBinding()] 2563 | Param( 2564 | [parameter(Mandatory=$true)] [String] $OutDir 2565 | ) 2566 | 2567 | $dir = $OutDir 2568 | 2569 | $file = "Get-ComputerInfo.txt" 2570 | [String []] $cmds = "Get-ComputerInfo" 2571 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2572 | 2573 | $file = "Verifier.txt" 2574 | [String []] $cmds = "verifier /querysettings" 2575 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2576 | 2577 | $file = "Powercfg.txt" 2578 | [String []] $cmds = "powercfg /List" 2579 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2580 | 2581 | $file = "Environment.txt" 2582 | [String []] $cmds = "Get-Variable -Name ""PSVersionTable"" -ValueOnly", 2583 | "date", 2584 | "Get-CimInstance ""Win32_OperatingSystem"" | select -ExpandProperty ""LastBootUpTime""", 2585 | "Get-CimInstance ""Win32_Processor"" | Format-List -Property *", 2586 | "systeminfo" 2587 | ExecCommandsAsync -OutDir $dir -File $file -Commands $cmds 2588 | } # Environment() 2589 | 2590 | # Registry files can vary in size significantly between runs 2591 | function WindowsRegistryDetail { 2592 | [CmdletBinding()] 2593 | Param( 2594 | [parameter(Mandatory=$true)] [String] $OutDir 2595 | ) 2596 | 2597 | $dir = $OutDir 2598 | $file = "RegistryFilesExportOperationStatus.txt" 2599 | New-Item -ItemType "directory" -Path "$OutDir\RegistryFiles" | Out-Null 2600 | [String []] $cmds = "reg export HKLM $OutDir\RegistryFiles\hklm.reg", 2601 | "reg export HKCU $OutDir\RegistryFiles\hkcu.reg", 2602 | "reg export HKCR $OutDir\RegistryFiles\hkcr.reg", 2603 | "reg export HKU $OutDir\RegistryFiles\hku.reg", 2604 | "reg export HKCC $OutDir\RegistryFiles\hkcc.reg" 2605 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2606 | 2607 | #Zip the Windows Registry files due to their large size 2608 | CreateZip -Src "$dir\RegistryFiles" -Out "$dir\RegistryFiles.zip" 2609 | Remove-Item "$dir\RegistryFiles" -Force -Recurse 2610 | } # WindowsRegistryDetail() 2611 | 2612 | function LocalhostDetail { 2613 | [CmdletBinding()] 2614 | Param( 2615 | [parameter(Mandatory=$true)] [String] $OutDir, 2616 | [parameter(Mandatory=$true)] [Bool] $SkipWindowsRegistry 2617 | ) 2618 | 2619 | $dir = (Join-Path -Path $OutDir -ChildPath "_Localhost") # sort to top 2620 | New-Item -ItemType directory -Path $dir | Out-Null 2621 | 2622 | if (-not $SkipWindowsRegistry) { 2623 | Start-Thread ${function:WindowsRegistryDetail} -Params @{OutDir=$dir} 2624 | } 2625 | 2626 | SystemLogs -OutDir $dir 2627 | ServicesDrivers -OutDir $dir 2628 | VMHostDetail -OutDir $dir 2629 | } # LocalhostDetail() 2630 | 2631 | function CustomModule { 2632 | [CmdletBinding()] 2633 | Param( 2634 | [parameter(Mandatory=$false)] [String[]] $Commands, # Passed in as [ScriptBlock[]] 2635 | [parameter(Mandatory=$true)] [String] $OutDir 2636 | ) 2637 | 2638 | if ($Commands.Count -eq 0) { 2639 | return 2640 | } 2641 | 2642 | $CustomModule = (Join-Path $OutDir "CustomModule") 2643 | New-Item -ItemType Directory -Path $CustomModule | Out-Null 2644 | 2645 | $file = "ExtraCommands.txt" 2646 | ExecCommands -OutDir $CustomModule -File $file -Commands $Commands 2647 | } # CustomModule() 2648 | 2649 | function Sanity { 2650 | [CmdletBinding()] 2651 | Param( 2652 | [parameter(Mandatory=$true)] [String] $OutDir, 2653 | [parameter(Mandatory=$true)] [Hashtable] $Params 2654 | ) 2655 | 2656 | $dir = $OutDir 2657 | 2658 | $file = "Get-ChildItem.txt" 2659 | [String []] $cmds = "Get-ChildItem -Path $OutDir -Exclude Get-NetView.log -File -Recurse | Get-FileHash -Algorithm SHA1 | Format-Table -AutoSize" 2660 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2661 | 2662 | $file = "Metadata.txt" 2663 | $out = Join-Path $dir $file 2664 | $paramString = if ($Params.Count -eq 0) {"None`n`n"} else {"`n$($Params | Out-String)"} 2665 | Write-Output "Script Version: $($Global:Version)" | Out-File -Encoding "default" -Append $out 2666 | Write-Output "Module Version: $($MyInvocation.MyCommand.Module.Version)" | Out-File -Encoding "default" -Append $out 2667 | Write-Output "Bound Parameters: $paramString" | Out-File -Encoding "default" -Append $out 2668 | 2669 | [String []] $cmds = "Get-FileHash -Path ""$PSCommandPath"" -Algorithm SHA1 | Format-List -Property *" 2670 | ExecCommands -OutDir $dir -File $file -Commands $cmds 2671 | } # Sanity() 2672 | 2673 | function LogPostProcess { 2674 | [CmdletBinding()] 2675 | Param( 2676 | [parameter(Mandatory=$true)] [String] $OutDir 2677 | ) 2678 | 2679 | $dir = $OutDir 2680 | $file = "Command-Time.log" 2681 | $out = Join-Path $dir $file 2682 | 2683 | $cmdData = Get-Content "$dir\Get-NetView.log" | where {$_ -like "(* ms)*"} 2684 | $table = $cmdData | foreach { 2685 | $time, $cmd = ($_ -replace "^\(\s*","") -split " ms\) " 2686 | [PSCustomObject] @{ 2687 | "Time (ms)" = $time -as [Int] 2688 | "Command" = $cmd 2689 | } 2690 | } 2691 | $table = $table | sort -Property "Time (ms)" -Descending 2692 | 2693 | $stats = $table."Time (ms)" | measure -Average -Sum 2694 | $roundedAvg = [Math]::Round($stats.Average, 2) 2695 | $lazyMedian = $table."Time (ms)"[$table.Count / 2] 2696 | $variance = ($table."Time (ms)" | foreach {[Math]::pow($_ - $stats.Average, 2)} | measure -Average).Average 2697 | $stdDev = [Math]::Round([Math]::Sqrt($variance), 2) 2698 | $timeSec = [Math]::Round($stats.Sum / 1000, 2) 2699 | 2700 | Write-Output "Average = $roundedAvg ms, Median = $lazyMedian ms, StdDev = $stdDev ms, Sum = $timeSec s, Count = $($stats.Count)" | Out-File -Encoding "default" -Append $out 2701 | Write-Output $table | Out-File -Encoding "default" -Width $columns -Append $out 2702 | } # LogPostProcess() 2703 | 2704 | # 2705 | # Setup & Validation Functions 2706 | # 2707 | 2708 | function CheckAdminPrivileges { 2709 | [CmdletBinding()] 2710 | Param( 2711 | [parameter(Mandatory=$true)] [Bool] $SkipAdminCheck 2712 | ) 2713 | 2714 | if (-not $SkipAdminCheck) { 2715 | # Yep, this is the easiest way to do this. 2716 | $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 2717 | if (-not $isAdmin) { 2718 | throw "Get-NetView : You do not have the required permission to complete this task. Please run this command in an Administrator PowerShell window or specify the -SkipAdminCheck option." 2719 | } 2720 | } 2721 | } # CheckAdminPrivileges() 2722 | 2723 | function NormalizeWorkDir { 2724 | [CmdletBinding()] 2725 | Param( 2726 | [parameter(Mandatory=$false)] [String] $OutputDirectory 2727 | ) 2728 | 2729 | # Output dir priority - $OutputDirectory, Desktop, Temp 2730 | $baseDir = if (-not [String]::IsNullOrWhiteSpace($OutputDirectory)) { 2731 | if (Test-Path $OutputDirectory) { 2732 | (Resolve-Path $OutputDirectory).Path # full path 2733 | } else { 2734 | throw "Get-NetView : The directory ""$OutputDirectory"" does not exist." 2735 | } 2736 | } elseif (($desktop = [Environment]::GetFolderPath("Desktop"))) { 2737 | $desktop 2738 | } else { 2739 | $env:TEMP 2740 | } 2741 | $workDirName = "msdbg.$env:COMPUTERNAME" 2742 | 2743 | return (Join-Path $baseDir $workDirName).TrimEnd("\") 2744 | } # NormalizeWorkDir() 2745 | 2746 | function EnvDestroy { 2747 | [CmdletBinding()] 2748 | Param( 2749 | [parameter(Mandatory=$true)] [String] $OutDir 2750 | ) 2751 | 2752 | If (Test-Path $OutDir) { 2753 | Remove-Item $OutDir -Recurse # Careful - Deletes $OurDir and all its contents 2754 | } 2755 | } # EnvDestroy() 2756 | 2757 | function EnvCreate { 2758 | [CmdletBinding()] 2759 | Param( 2760 | [parameter(Mandatory=$true)] [String] $OutDir 2761 | ) 2762 | 2763 | # Attempt to create working directory, stopping on failure. 2764 | New-Item -ItemType directory -Path $OutDir -ErrorAction Stop | Out-Null 2765 | } # EnvCreate() 2766 | 2767 | function Initialize { 2768 | [CmdletBinding()] 2769 | Param( 2770 | [parameter(Mandatory=$true)] [Int] $BackgroundThreads, 2771 | [parameter(Mandatory=$true)] [Int] $Timeout, 2772 | [parameter(Mandatory=$true)] [Double] $ExecutionRate, 2773 | [parameter(Mandatory=$true)] [String] $OutDir 2774 | ) 2775 | 2776 | $Global:ExecParams = @{ 2777 | StartTime = Get-Date 2778 | Timeout = $Timeout 2779 | DelayFactor = (1 / $ExecutionRate) - 1 2780 | } 2781 | 2782 | # Remove color codes from output. 2783 | if ($PSVersionTable.PSVersion -ge "7.2") { 2784 | $PSStyle.OutputRendering = [System.Management.Automation.OutputRendering]::Host 2785 | } 2786 | 2787 | # Setup output folder 2788 | EnvDestroy $OutDir 2789 | EnvCreate $OutDir 2790 | 2791 | Start-Transcript -Path "$OutDir\Get-NetView.log" 2792 | 2793 | if ($ExecutionRate -lt 1) { 2794 | Write-Host "Forcing BackgroundThreads=0 because ExecutionRate is less than 1." 2795 | $BackgroundThreads = 0 2796 | } 2797 | 2798 | Open-GlobalRunspacePool -BackgroundThreads $BackgroundThreads 2799 | } # Initialize() 2800 | 2801 | function Completion { 2802 | [CmdletBinding()] 2803 | Param( 2804 | [parameter(Mandatory=$true)] [String] $Src 2805 | ) 2806 | 2807 | $logDir = (Join-Path -Path $Src -ChildPath "_Logs") 2808 | New-Item -ItemType directory -Path $logDir | Out-Null 2809 | 2810 | # Override timeout for post-processing. 2811 | $Global:ExecParams.Timeout = [Int]::MaxValue 2812 | 2813 | Close-GlobalRunspacePool 2814 | 2815 | Write-Progress -Activity $Global:FinishActivity -Status "Processing output..." 2816 | Sanity -OutDir $logDir -Params $PSBoundParameters 2817 | 2818 | # Collect statistics 2819 | $timestamp = $Global:ExecParams.StartTime | Get-Date -f yyyy.MM.dd_hh.mm.ss 2820 | 2821 | $dirs = (Get-ChildItem $Src -Recurse | Measure-Object -Property length -Sum) # out folder size 2822 | $hash = (Get-FileHash -Path $MyInvocation.PSCommandPath -Algorithm "SHA1").Hash # script hash 2823 | 2824 | # Display version and file save location 2825 | Write-Host "" 2826 | Write-Host "Diagnostics Data:" 2827 | Write-Host "-----------------" 2828 | Write-Host "Get-NetView" 2829 | Write-Host "Version: $($Global:Version)" 2830 | Write-Host "SHA1: $(if ($hash) {$hash} else {"N/A"})" 2831 | Write-Host "" 2832 | Write-Host $Src 2833 | Write-Host "Size: $("{0:N2} MB" -f ($dirs.sum / 1MB))" 2834 | Write-Host "Dirs: $((Get-ChildItem $Src -Directory -Recurse | Measure-Object).Count)" 2835 | Write-Host "Files: $((Get-ChildItem $Src -File -Recurse | Measure-Object).Count)" 2836 | Write-Host "" 2837 | Write-Host "Execution Time:" 2838 | Write-Host "---------------" 2839 | $delta = (Get-Date) - $Global:ExecParams.StartTime 2840 | Write-Host "$($delta.Minutes) Min $($delta.Seconds) Sec" 2841 | Write-Host "" 2842 | 2843 | try { 2844 | Stop-Transcript | Out-Null 2845 | Move-Item -Path "$Src\Get-NetView.log" -Destination "$logDir\Get-NetView.log" 2846 | Write-Host "Transcript stopped, output file is $logDir\Get-NetView.log" 2847 | LogPostProcess -OutDir $logDir 2848 | } catch { 2849 | Write-Output "Stop-Transcript failed" | Out-File -Encoding "default" -Append "$logDir\Get-NetView.log" 2850 | } 2851 | 2852 | Write-Progress -Activity $Global:FinishActivity -Status "Creating zip..." 2853 | $outzip = "$Src-$timestamp.zip" 2854 | CreateZip -Src $Src -Out $outzip 2855 | Write-Host $outzip 2856 | Write-Host "Size: $("{0:N2} MB" -f ((Get-Item $outzip).Length / 1MB))" 2857 | 2858 | Write-Progress -Activity $Global:FinishActivity -Completed 2859 | } # Completion() 2860 | 2861 | <# 2862 | .SYNOPSIS 2863 | Collects data on system and network configuration for diagnosing Microsoft Networking. 2864 | 2865 | .DESCRIPTION 2866 | Collects comprehensive configuration data to aid in troubleshooting Microsoft Network issues. 2867 | Data is collected from the following sources: 2868 | - Get-NetView metadata (path, args, etc.) 2869 | - Environment (OS, hardware, domain, hostname, etc.) 2870 | - Physical, virtual, Container, NICs 2871 | - Network Configuration, IP Addresses, MAC Addresses, Neighbors, Routes 2872 | - Physical Switch configuration, QOS polices 2873 | - Virtual Machine configuration 2874 | - Virtual Switches, Bridges, NATs 2875 | - Device Drivers 2876 | - Performance Counters 2877 | - Logs, Traces, etc. 2878 | - System and Application Events 2879 | 2880 | The data is collected in a folder on the Desktop (by default), which is zipped on completion. 2881 | Use Feedback hub to submit a new feedback. Select one of these Categories: 2882 | Network and Internet -> Virtual Networking 2883 | Network and Internet -> Connecting to an Ethernet Network. 2884 | Attach the Zip file to the feedback and submit. 2885 | 2886 | Do not share the zip file over email or other file sharing tools. Only submit the file through the feedback hub. 2887 | 2888 | The output is most easily viewed with Visual Studio Code or similar editor with a navigation panel. 2889 | 2890 | .PARAMETER OutputDirectory 2891 | Optional path to the directory where the output should be saved. Can be either a relative or an absolute path. 2892 | If unspecified, the current user's Desktop will be used by default. 2893 | 2894 | .PARAMETER ExtraCommands 2895 | Optional list of additional commands, given as ScriptBlocks. Their output is saved to the CustomModule directory, 2896 | which can be accessed by using "$CustomModule" as a placeholder. For example, {Copy-Item .\MyFile.txt $CustomModule} 2897 | copies "MyFile.txt" to "CustomModule\MyFile.txt". 2898 | 2899 | .PARAMETER BackgroundThreads 2900 | Maximum number of background tasks, from 0 - 16. Defaults to 5. 2901 | 2902 | .PARAMETER Timeout 2903 | Amount of time, in minutes, to wait for all commands to complete. Note that total runtime may be greater due to 2904 | post-processing. Defaults to 120 minutes. 2905 | 2906 | .PARAMETER ExecutionRate 2907 | Relative rate at which commands are executed, with 1 being normal speed. Reduce to slow down execution and spread 2908 | CPU usage over time. Useful on live or production systems to avoid disruption. 2909 | 2910 | NOTE: This will force BackgroundThreads = 0. 2911 | 2912 | .PARAMETER SkipAdminCheck 2913 | If present, skip the check for admin privileges before execution. Note that without admin privileges, the scope and 2914 | usefulness of the collected data is limited. 2915 | 2916 | .PARAMETER SkipLogs 2917 | If present, skip the EVT and WER logs gather phases. 2918 | 2919 | .PARAMETER SkipNetsh 2920 | If present, skip all Netsh commands. 2921 | 2922 | .PARAMETER SkipNetshTrace 2923 | If present, skip the Netsh Trace data gather phase. 2924 | 2925 | .PARAMETER SkipCounters 2926 | If present, skip the Windows Performance Counters collection phase. 2927 | 2928 | .PARAMETER SkipWindowsRegistry 2929 | If present, skip exporting Windows Registry keys. 2930 | 2931 | .PARAMETER SkipVm 2932 | If present, skip the Virtual Machine (VM) data gather phases. 2933 | 2934 | .PARAMETER SkipOnline 2935 | If present, skip the Online data gather phases. 2936 | 2937 | .PARAMETER SkipSMBEvents 2938 | If present, skips collecting of SMB Events. 2939 | 2940 | .PARAMETER SkipPktMon 2941 | If present, skips collecting PktMon information 2942 | 2943 | .PARAMETER SkipNvspInfo 2944 | If present, skips collecting NvspInfo information. 2945 | 2946 | .EXAMPLE 2947 | Get-NetView -OutputDirectory ".\" 2948 | Runs Get-NetView and outputs to the current working directory. 2949 | 2950 | .LINK 2951 | https://github.com/microsoft/Get-NetView 2952 | #> 2953 | function Get-NetView { 2954 | [CmdletBinding()] 2955 | Param( 2956 | [parameter(Mandatory=$false)] 2957 | [ValidateScript({Test-Path $_ -PathType Container})] 2958 | [String] $OutputDirectory = "", 2959 | 2960 | [parameter(Mandatory=$false)] 2961 | [ScriptBlock[]] $ExtraCommands = @(), 2962 | 2963 | [Alias("MaxThreads")] 2964 | [parameter(Mandatory=$false, ParameterSetName="BackgroundThreads")] 2965 | [ValidateRange(0, 16)] 2966 | [Int] $BackgroundThreads = 5, 2967 | 2968 | [parameter(Mandatory=$false)] 2969 | [ValidateRange(0, [Int]::MaxValue)] 2970 | [Int] $Timeout = 120, 2971 | 2972 | [parameter(Mandatory=$false)] 2973 | [ValidateRange(0.0001, 1)] 2974 | [Double] $ExecutionRate = 1, 2975 | 2976 | [parameter(Mandatory=$false)] [Switch] $SkipAdminCheck = $false, 2977 | [parameter(Mandatory=$false)] [Switch] $SkipLogs = $false, 2978 | [parameter(Mandatory=$false)] [Switch] $SkipNetsh = $false, 2979 | [parameter(Mandatory=$false)] [Switch] $SkipNetshTrace = $false, 2980 | [parameter(Mandatory=$false)] [Switch] $SkipCounters = $false, 2981 | [parameter(Mandatory=$false)] [Switch] $SkipWindowsRegistry = $false, 2982 | [parameter(Mandatory=$false)] [Switch] $SkipSMBEvents = $false, 2983 | [parameter(Mandatory=$false)] [Switch] $SkipOnline = $false, 2984 | [parameter(Mandatory=$false)] [Switch] $SkipVm = $false, 2985 | [parameter(Mandatory=$false)] [Switch] $SkipPktMon = $false, 2986 | [parameter(Mandatory=$false)] [Switch] $SkipNvspInfo = $false 2987 | ) 2988 | 2989 | # Input Validation 2990 | CheckAdminPrivileges $SkipAdminCheck 2991 | $workDir = NormalizeWorkDir -OutputDirectory $OutputDirectory 2992 | 2993 | Initialize -BackgroundThreads $BackgroundThreads -Timeout $Timeout -ExecutionRate $ExecutionRate -OutDir $workDir 2994 | 2995 | # Import exec commands into script context 2996 | . $ExecFunctions -ExecParams $Global:ExecParams 2997 | Remove-Item alias:Write-CmdLog -ErrorAction "SilentlyContinue" 2998 | 2999 | # Start Run 3000 | try { 3001 | CustomModule -OutDir $workDir -Commands $ExtraCommands 3002 | 3003 | Write-Progress -Activity $Global:QueueActivity 3004 | 3005 | if (-not $SkipNetsh) { 3006 | Start-Thread ${function:NetshDetail} -Params @{OutDir=$workDir; SkipNetshTrace=$SkipNetshTrace} 3007 | } 3008 | 3009 | if (-not $SkipCounters) { 3010 | Start-Thread ${function:CounterDetail} -Params @{OutDir=$workDir} 3011 | } 3012 | 3013 | Environment -OutDir $workDir 3014 | LocalhostDetail -OutDir $workDir -SkipWindowsRegistry $SkipWindowsRegistry 3015 | NetworkSummary -OutDir $workDir 3016 | NetSetupDetail -OutDir $workDir 3017 | NicDetail -OutDir $workDir 3018 | OneX -OutDir $workDir 3019 | 3020 | QosDetail -OutDir $workDir 3021 | SMBDetail -OutDir $workDir 3022 | NetIp -OutDir $workDir 3023 | NetNatDetail -OutDir $workDir 3024 | HNSDetail -OutDir $workDir 3025 | ATCDetail -OutDir $workDir 3026 | if (-not $SkipPktMon) { 3027 | PktmonDetail -OutDir $workDir 3028 | } 3029 | 3030 | Show-Threads 3031 | } catch { 3032 | $msg = $($_ | Out-String) + "`nStack Trace:`n" + $_.ScriptStackTrace 3033 | ExecControlError -OutDir $workDir -Message $msg 3034 | 3035 | throw $_ 3036 | } finally { 3037 | Completion -Src $workDir 3038 | } 3039 | } # Get-NetView 3040 | 3041 | # For backwards compat, support direct execution as a .ps1 file (no dot sourcing needed). 3042 | if (-not [String]::IsNullOrEmpty($MyInvocation.InvocationName)) { 3043 | if (($MyInvocation.InvocationName -eq "&") -or 3044 | ($MyInvocation.MyCommand.Path -eq (Resolve-Path -Path $MyInvocation.InvocationName).ProviderPath)) { 3045 | Get-NetView @args 3046 | } 3047 | } 3048 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/rkdclcowkjlh5uu3?svg=true)](https://ci.appveyor.com/project/MSFTCoreNet/get-netview) 2 | [![downloads](https://img.shields.io/powershellgallery/dt/Get-NetView.svg?label=downloads)](https://www.powershellgallery.com/packages/Get-NetView) 3 | 4 | # Description 5 | Get-NetView is a tool that collects local system and network configuration data, to streamline diagnosis of Windows networking issues. 6 | 7 | # Installation 8 | ## PowerShell Gallery 9 | To install this module from [PowerShell Gallery](https://www.powershellgallery.com/), run: 10 | ```PowerShell 11 | Install-Module Get-NetView -SkipPublisherCheck -Force 12 | ``` 13 | It is also part of `MSFT.Network.Diag`, which can be installed with: 14 | ```PowerShell 15 | Install-Module MSFT.Network.Diag 16 | ``` 17 | 18 | ## Disconnected or air-gapped systems 19 | If your servers are disconnected or air-gapped, use: 20 | ```PowerShell 21 | Save-Module Get-NetView C:\SomeFolderPath 22 | ``` 23 | Then move the Get-NetView folder (from `C:\SomeFolderPath`) to `C:\Program Files\WindowsPowerShell\Modules` on your target server. 24 | 25 | ## Direct Execution 26 | This script also supports direct execution: 27 | ```PowerShell 28 | Invoke-WebRequest "aka.ms/Get-NetView" -OutFile "Get-NetView.ps1" 29 | .\Get-NetView.ps1 -OutputDir .\ 30 | ``` 31 | If blocked by execution policy: 32 | ```PowerShell 33 | Powershell.exe -ExecutionPolicy Bypass -File .\Get-NetView.ps1 -OutputDir .\ 34 | ``` 35 | 36 | # Usage 37 | To begin data collection, simply run: 38 | ```PowerShell 39 | Get-NetView 40 | ``` 41 | The output is saved to `Desktop\msdbg.`, and can be inspected with any file manager. On completion, a .zip file is created for easy sharing. 42 | 43 | For additional help and advanced options, run: 44 | ```PowerShell 45 | Get-Help Get-NetView 46 | ``` 47 | 48 | This tool is also run automatically by [Get-SDDCDiagnosticInfo](https://github.com/PowerShell/PrivateCloud.DiagnosticInfo) by including the -IncludeGetNetView parameter. 49 | 50 | # :star: More by the Microsoft Core Networking team 51 | Find more from the Core Networking team using the [MSFTNet](https://github.com/topics/msftnet) topic. 52 | 53 | To see all modules from the Microsoft Core Networking team, use: 54 | ```PowerShell 55 | Find-Module -Tag MSFTNet 56 | ``` 57 | 58 | # Contributing 59 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 60 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 61 | the rights to use your contribution. For details, visit https://cla.microsoft.com. 62 | 63 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide 64 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions 65 | provided by the bot. You will only need to do this once across all repos using our CLA. 66 | 67 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 68 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 69 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 70 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # YAML Reference Guide : https://www.appveyor.com/docs/appveyor-yml/ 2 | # Environmental Variables Guide : https://www.appveyor.com/docs/environment-variables/ 3 | # YAML Validator : https://ci.appveyor.com/tools/validate-yaml 4 | # AppVeyor Build Pipeline : https://www.appveyor.com/docs/build-configuration/ 5 | # GitHub push with tokens : https://www.appveyor.com/docs/how-to/git-push/ 6 | 7 | # Repo cloned into this folder on the build worker 8 | clone_folder: c:\projects\Get-NetView 9 | 10 | init: 11 | - ps: $Env:repoName = $($env:APPVEYOR_REPO_NAME.Split('/')[1]) 12 | - ps: $version = "$(Get-Date -format yyyy.MM.dd).$env:appveyor_build_number" 13 | - ps: Update-AppveyorBuild -Version $version 14 | 15 | # Install script prior to running tests 16 | install: 17 | - ps: . .\tests\setup\install.ps1 18 | 19 | # Initiate tests 20 | test_script: 21 | - ps: . .\tests\setup\initiate-tests.ps1 22 | 23 | # finalize build 24 | deploy_script: 25 | - ps: . .\tests\setup\deploy.ps1 26 | 27 | version: '{build}' 28 | 29 | # Environment variables for PowerShell Gallery (NuGetAPIKey) and GitHub (GitHubKey) API key for publishing updates 30 | # - The "secure:" value is the Appveyor encryption of the key 31 | # - GitHub update occurs to ensure that the module version is incremented based on the build number 32 | 33 | #CoreNetBuilder 34 | environment: 35 | NuGetApiKey: 36 | secure: yM66usk26GL3IV6hGkA0AZsCznJKtjBnzuKEGzbN5WpK+AT7rOXmNKxj6kfAR7EZ 37 | GitHubKey: 38 | secure: gYdPKtnKDlG0egxhhmZ0rYqHlLn2+V/qsqlIouXC/LypImn8KF7eBUKtwcMCGmz5 39 | APPVEYOR_RDP_PASSWORD: 40 | secure: q9cNMN8o/tkzFDvDf+npkj5MOgFVGOLnJokZq/d4BUY= 41 | 42 | # Disable automatic builds; Without this, the following error shows up: 43 | # "Specify a project or solution file. The directory does not contain a project or solution file." 44 | build: "off" 45 | 46 | max_jobs: 1 47 | 48 | # Ignore testing a commit if specific strings used in commit message: updated readme, update readme, update docs, update version, update appveyor 49 | skip_commits: 50 | message: /updated readme.*|update readme.*s|update docs.*|update version.*|update appveyor.*/ 51 | files: 52 | - README.md 53 | 54 | # There's no need to alter the build number for a Pull Request (PR) since they don't modify anything 55 | #pull_requests: 56 | # do_not_increment_build_number: true 57 | 58 | #on_finish: 59 | # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) 60 | -------------------------------------------------------------------------------- /tests/results/TestResults.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/setup/deploy.ps1: -------------------------------------------------------------------------------- 1 | git config --global credential.helper store 2 | 3 | Add-Content "$env:USERPROFILE\.git-credentials" "https://$($env:GitHubKey):x-oauth-basic@github.com`n" 4 | 5 | git config --global user.email "dcuomo@outlook.com" 6 | git config --global user.name "Dan Cuomo" 7 | git config --global core.autocrlf false 8 | git config --global core.safecrlf false 9 | 10 | # Line break for readability in AppVeyor console 11 | Write-Host -Object '' 12 | 13 | $versionUpdateCommitMsg = "Update version to {0}" 14 | $filesToPublish = @("Get-NetView.psd1", "Get-NetView.psm1", "LICENSE", "README.md") 15 | 16 | # Make sure we're using the Master branch and that it's not a pull request 17 | # Environmental Variables Guide: https://www.appveyor.com/docs/environment-variables/ 18 | if ($env:APPVEYOR_REPO_BRANCH -ne 'master') { 19 | Write-Warning -Message "Skipping version increment and publish for branch $env:APPVEYOR_REPO_BRANCH" 20 | } elseif ($env:APPVEYOR_PULL_REQUEST_NUMBER -gt 0) { 21 | Write-Warning -Message "Skipping version increment and publish for pull request #$env:APPVEYOR_PULL_REQUEST_NUMBER" 22 | } else { 23 | try { 24 | # This is where the module manifest lives 25 | $manifestPath = ".\$($env:RepoName).psd1" 26 | 27 | # Start by importing the manifest to determine the version 28 | $manifest = Test-ModuleManifest -Path $manifestPath -ErrorAction SilentlyContinue 29 | $oldVersion = $manifest.Version 30 | $newVersion = [Version]::new($env:APPVEYOR_BUILD_VERSION -split "/.") # expected format "yyyy.MM.dd.{build}" 31 | 32 | # Check if a published file is updated 33 | $lastVersionUpdate = git log --grep ($versionUpdateCommitMsg -f $oldVersion) --format=format:"%H" 34 | $modifiedFiles = git diff HEAD $lastVersionUpdate --name-only 35 | $needToPublish = $filesToPublish | where {$modifiedFiles -like "$_"} 36 | 37 | if (-not $needToPublish) { 38 | Write-Warning -Message "No changes to published files." 39 | return 40 | } 41 | 42 | Write-Output "Old Version: $oldVersion" 43 | Write-Output "New Version: $newVersion" 44 | 45 | # Update the manifest with the new version value and fix the weird string replace bug 46 | #$functionList = ((Get-ChildItem -Path .\$($env:RepoName)).BaseName) 47 | $splat = @{ 48 | 'Path' = $manifestPath 49 | 'ModuleVersion' = $newVersion 50 | #'FunctionsToExport' = $functionList 51 | 'Copyright' = "(c) $( (Get-Date).Year ) Inc. All rights reserved." 52 | } 53 | 54 | Update-ModuleManifest @splat -ErrorAction SilentlyContinue 55 | (Get-Content -Path $manifestPath) -replace "PSGet_$($env:RepoName)", "$($env:RepoName)" | Set-Content -Path $manifestPath 56 | (Get-Content -Path $manifestPath) -replace 'NewManifest', "$($env:RepoName)" | Set-Content -Path $manifestPath 57 | #(Get-Content -Path $manifestPath) -replace 'FunctionsToExport = ', 'FunctionsToExport = @(' | Set-Content -Path $manifestPath -Force 58 | #(Get-Content -Path $manifestPath) -replace "$($functionList[-1])'", "$($functionList[-1])')" | Set-Content -Path $manifestPath -Force 59 | 60 | # Update Get-NetView.psm1 version to match module 61 | $getNetViewPath = ".\Get-NetView.psm1" 62 | 63 | $versionRegex = "\`$Global:Version = `"\d+\.\d+.\d+\.\d+`"`n" 64 | $versionUpdate = "`$Global:Version = `"$newVersion`"`n" 65 | $(Get-Content -Path $getNetViewPath -Raw) -replace $versionRegex, $versionUpdate | Set-Content -Path $getNetViewPath -NoNewline 66 | } catch { 67 | throw $_ 68 | } 69 | 70 | # Create a temp folder with just the files we want to publish to PowerShell Gallery 71 | # Otherwise, everything will be published, including the .git folder. 72 | $publishedFolder = ".\published\Get-NetView" # leaf dir MUST be named "Get-NetView" 73 | try { 74 | if (Test-Path $publishedFolder) { 75 | Remove-Item -Path $publishedFolder -Recurse -Force 76 | } 77 | 78 | New-Item -ItemType Directory -Path $publishedFolder 79 | $filesToPublish | foreach {Copy-Item -Path ".\$_" -Destination "$publishedFolder"} 80 | } catch { 81 | Write-Warning "Failed to create publishing folder." 82 | throw $_ 83 | } 84 | 85 | Get-ChildItem $publishedFolder 86 | 87 | # Publish the new version to the PowerShell Gallery 88 | try { 89 | # Build a splat containing the required details and make sure to Stop for errors which will trigger the catch 90 | $PM = @{ 91 | Path = $publishedFolder 92 | NuGetApiKey = $env:NuGetApiKey 93 | ErrorAction = 'Stop' 94 | Force = $true 95 | } 96 | 97 | Publish-Module @PM 98 | Write-Host "$($env:RepoName) PowerShell Module version $newVersion published to the PowerShell Gallery." -ForegroundColor Cyan 99 | } catch { 100 | Write-Warning "Publishing update $newVersion to the PowerShell Gallery failed." 101 | throw $_ 102 | } 103 | 104 | # Publish the new version back to Master on GitHub 105 | try { 106 | # Set up a path to the git.exe cmd, import posh-git to give us control over git, and then push changes to GitHub 107 | # Note that "update version" is included in the appveyor.yml file's "skip a build" regex to avoid a loop 108 | $env:Path += ";$env:ProgramFiles\Git\cmd" 109 | Import-Module posh-git -ErrorAction Stop 110 | git checkout master -q 111 | git add --all 112 | git status 113 | git commit -s -m "Update version to $newVersion" 114 | git push origin master -q 115 | Write-Host "$($env:RepoName) PowerShell Module version $newVersion published to GitHub." -ForegroundColor Cyan 116 | } catch { 117 | Write-Warning "Publishing update $newVersion to GitHub failed." 118 | throw $_ 119 | } 120 | } -------------------------------------------------------------------------------- /tests/setup/initiate-tests.ps1: -------------------------------------------------------------------------------- 1 | # Invoke Pester to run tests, then save the results in NUnitXML to populate the AppVeyor tests section 2 | # Pester : https://github.com/pester/Pester/wiki 3 | # Pester Code Coverage : https://info.sapien.com/index.php/scripting/scripting-modules/testing-pester-code-coverage 4 | 5 | New-Item -Path .\tests -Name results -ItemType Directory -Force 6 | 7 | $testResultPath = '.\tests\results\TestResults.xml' 8 | # This is a manifest so no code coverage is possible. Original line kept below: 9 | #...\results\TestsResults.xml -PassThru -CodeCoverage .\MSFTNetworking.Tools.psd1 10 | $res = Invoke-Pester -Script ".\tests\unit" -OutputFormat NUnitXml -OutputFile $testResultPath -PassThru 11 | 12 | (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultPath)) 13 | 14 | if ($res.FailedCount -gt 0) { throw "$($res.FailedCount) tests failed." } 15 | -------------------------------------------------------------------------------- /tests/setup/install.ps1: -------------------------------------------------------------------------------- 1 | git clone -q https://github.com/PowerShell/DscResource.Tests 2 | 3 | Import-Module -Name "$env:APPVEYOR_BUILD_FOLDER\DscResource.Tests\AppVeyor.psm1" 4 | Invoke-AppveyorInstallTask 5 | 6 | [string[]]$PowerShellModules = @("Pester", 'posh-git', 'psake', 'poshspec', 'PSScriptAnalyzer') 7 | 8 | $ModuleManifest = Test-ModuleManifest .\$($env:RepoName).psd1 -ErrorAction SilentlyContinue 9 | $repoRequiredModules = $ModuleManifest.RequiredModules.Name 10 | 11 | if ($repoRequiredModules) { $PowerShellModules += $repoRequiredModules } 12 | 13 | # This section is taken care of by Invoke-AppVeyorInstallTask 14 | <#[string[]]$PackageProviders = @('NuGet', 'PowerShellGet') 15 | 16 | # Install package providers for PowerShell Modules 17 | ForEach ($Provider in $PackageProviders) { 18 | If (!(Get-PackageProvider $Provider -ErrorAction SilentlyContinue)) { 19 | Install-PackageProvider $Provider -Force -ForceBootstrap -Scope CurrentUser 20 | } 21 | }#> 22 | 23 | # Install the PowerShell Modules 24 | ForEach ($Module in $PowerShellModules) { 25 | If (!(Get-Module -ListAvailable $Module -ErrorAction SilentlyContinue)) { 26 | Install-Module $Module -Scope CurrentUser -Force -Repository PSGallery 27 | } 28 | 29 | Import-Module $Module 30 | } 31 | -------------------------------------------------------------------------------- /tests/unit/unit.tests.ps1: -------------------------------------------------------------------------------- 1 | Describe "$($env:repoName)-Manifest" { 2 | Context Validation { 3 | It "[Import-PowerShellDataFile] - $($env:repoName).psd1 is a valid PowerShell Data File" { 4 | $DataFile = Import-PowerShellDataFile .\$($env:repoName).psd1 5 | $DataFile | Should -Not -BeNullOrEmpty 6 | } 7 | 8 | It "[Test-ModuleManifest] - $($env:repoName).psd1 should pass the basic test" { 9 | $TestModule = Test-ModuleManifest .\$($env:repoName).psd1 10 | $TestModule | Should -Not -BeNullOrEmpty 11 | } 12 | 13 | It "Should have the $($env:repoName) function available" { 14 | Import-Module .\$($env:repoName).psd1 15 | $command = Get-Command $($env:repoName) 16 | $command | Should -Not -BeNullOrEmpty 17 | } 18 | } 19 | } 20 | --------------------------------------------------------------------------------