diff --git a/public/Read-DbaXEFile.ps1 b/public/Read-DbaXEFile.ps1 index e211da1bcb..cd87b6c804 100644 --- a/public/Read-DbaXEFile.ps1 +++ b/public/Read-DbaXEFile.ps1 @@ -6,11 +6,15 @@ function Read-DbaXEFile { .DESCRIPTION Read XEvents from a *.xel or *.xem file. + The file that the XESession is currently writing to can not be accessed and will be skipped using pipeline input from Get-DbaXESession. + .PARAMETER Path The path to the *.xem or *.xem file. This is relative to the computer executing the command. UNC paths are supported. + Piping from Get-DbaXESession is also supported. + .PARAMETER Raw - If this switch is enabled, the Microsoft.SqlServer.XEvent.Linq.PublishedEvent enumeration object will be returned. + If this switch is enabled, an array of Microsoft.SqlServer.XEvent.XELite.XEvent objects will be returned. .PARAMETER EnableException By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. @@ -39,7 +43,7 @@ function Read-DbaXEFile { Returns events from all .xel files in C:\temp\xe. .EXAMPLE - PS C:\> Get-DbaXESession -SqlInstance sql2014 -Session deadlocks | Read-DbaXEFile + PS C:\> Get-DbaXESession -SqlInstance sql2019 -Session deadlocks | Read-DbaXEFile Reads remote XEvents by accessing the file over the admin UNC share. @@ -54,83 +58,87 @@ function Read-DbaXEFile { ) process { if (Test-FunctionInterrupt) { return } - foreach ($file in $path) { + foreach ($pathObject in $Path) { # in order to ensure CSV gets all fields, all columns will be # collected and output in the first (all all subsequent) object $columns = @("name", "timestamp") - if ($file -is [System.String]) { - $currentfile = $file - #Variable marked as unused by PSScriptAnalyzer - #$manualadd = $true - } elseif ($file -is [System.IO.FileInfo]) { - $currentfile = $file.FullName - #Variable marked as unused by PSScriptAnalyzer - #$manualadd = $true - } else { - if ($file -isnot [Microsoft.SqlServer.Management.XEvent.Session]) { - Stop-Function -Message "Unsupported file type." - return - } - - if ($file.TargetFile.Length -eq 0) { - Stop-Function -Message "This session does not have an associated Target File." - return + if ($pathObject -is [System.String]) { + $files = $pathObject + } elseif ($pathObject -is [System.IO.FileInfo]) { + $files = $pathObject.FullName + } elseif ($pathObject -is [Microsoft.SqlServer.Management.XEvent.Session]) { + if ($pathObject.TargetFile.Length -eq 0) { + Stop-Function -Message "The session [$pathObject] does not have an associated Target File." -Continue } - $instance = [dbainstance]$file.ComputerName - + $instance = [DbaInstance]$pathObject.ComputerName if ($instance.IsLocalHost) { - $currentfile = $file.TargetFile + $targetFile = $pathObject.TargetFile } else { - $currentfile = $file.RemoteTargetFile + $targetFile = $pathObject.RemoteTargetFile } - } - - $accessible = Test-Path -Path $currentfile - $whoami = whoami - if (-not $accessible) { - if ($file.Status -eq "Stopped") { continue } - Stop-Function -Continue -Message "$currentfile cannot be accessed from $($env:COMPUTERNAME). Does $whoami have access?" - } - - if ($Raw) { - return (SqlServer.XEvent\Read-SqlXEvent -FileName $currentfile) - } - - # use the SqlServer.XEvent\Read-SqlXEvent cmdlet from Microsoft - # because the underlying Class uses Tasks - # which is hard to handle in PowerShell - - $enum = SqlServer.XEvent\Read-SqlXEvent -FileName $currentfile - $newcolumns = ($enum.Fields.Name | Select-Object -Unique) - - $actions = ($enum.Actions.Name | Select-Object -Unique) - foreach ($action in $actions) { - $newcolumns += ($action -Split '\.')[-1] + $targetFile = $targetFile.Replace('.xel', '*.xel').Replace('.xem', '*.xem') + $files = Get-ChildItem -Path $targetFile | Sort-Object LastWriteTime + if ($pathObject.Status -eq 'Running') { + $files = $files | Select-Object -SkipLast 1 + } + Write-Message -Level Verbose -Message "Received $($files.Count) files based on [$targetFile]" + } else { + Stop-Function -Message "The Path [$pathObject] has an unsupported file type of [$($pathObject.GetType().FullName)]." } - $newcolumns = $newcolumns | Sort-Object - $columns = ($columns += $newcolumns) | Select-Object -Unique - - # Make it selectable, otherwise it's a weird enumeration - foreach ($event in $enum) { - $hash = [ordered]@{ } - - foreach ($column in $columns) { - $null = $hash.Add($column, $event.$column) + foreach ($file in $files) { + if (-not (Test-Path -Path $file)) { + Stop-Function -Message "$file cannot be accessed from $($env:COMPUTERNAME)." -Continue } - foreach ($key in $event.Actions.Keys) { - $hash[$key] = $event.Actions[$key] - } + # use the SqlServer\Read-SqlXEvent cmdlet from Microsoft + # because the underlying Class uses Tasks + # which is hard to handle in PowerShell - foreach ($key in $event.Fields.Keys) { - $hash[$key] = $event.Fields[$key] + if ($Raw) { + try { + Read-XEvent -FileName $file + } catch { + Stop-Function -Message "Failure" -ErrorRecord $_ -Target $file -Continue + } + } else { + try { + $enum = Read-XEvent -FileName $file + } catch { + Stop-Function -Message "Failure" -ErrorRecord $_ -Target $file -Continue + } + $newcolumns = ($enum.Fields.Name | Select-Object -Unique) + + $actions = ($enum.Actions.Name | Select-Object -Unique) + foreach ($action in $actions) { + $newcolumns += ($action -Split '\.')[-1] + } + + $newcolumns = $newcolumns | Sort-Object + $columns = ($columns += $newcolumns) | Select-Object -Unique + + # Make it selectable, otherwise it's a weird enumeration + foreach ($event in $enum) { + $hash = [ordered]@{ } + + foreach ($column in $columns) { + $null = $hash.Add($column, $event.$column) + } + + foreach ($key in $event.Actions.Keys) { + $hash[$key] = $event.Actions[$key] + } + + foreach ($key in $event.Fields.Keys) { + $hash[$key] = $event.Fields[$key] + } + + [PSCustomObject]$hash + } } - - [pscustomobject]$hash } } }