ConvertToSQLNoteBook.ps1
function loadScriptDomModules{ #try {Import-Module SqlServer -ErrorAction Stop} catch {Install-Module -Name SqlServer -Scope CurrentUser} finally {Import-Module SqlServer} Import-Module -Name SqlServer $ScriptDom = Join-Path -Path (Get-Module -Name SqlServer).ModuleBase -ChildPath 'Microsoft.SqlServer.TransactSql.ScriptDom.dll' if((Test-Path $ScriptDom) -eq $true ) {Add-Type -LiteralPath $ScriptDom} } # Quick Helper-function to turn the file into a script fragment, using scriptdom. function Get-ParsedSql($ScriptPath){ loadScriptDomModules [Microsoft.SqlServer.TransactSql.ScriptDom.TSql150Parser] $parser = new-object Microsoft.SqlServer.TransactSql.ScriptDom.TSql150Parser($false) $Reader = New-Object -TypeName System.IO.StreamReader -ArgumentList $ScriptPath $Errors = $null $ScriptFrag = $parser.Parse($Reader, [ref]$Errors) return $ScriptFrag } function Get-ParsedSqlOffsets{ [CmdletBinding()] param( $ScriptPath, $IncludeGaps=$true, [switch]$ExtractCommentsInsideBatches ) <################################################################################################# Checking for Batch length #################################################################################################> $s = Get-Content -Raw ( Resolve-Path $ScriptPath ) $ParsedSql = Get-ParsedSql $ScriptPath $SqlBatches = @() $SqlBatch = @() $id=1 foreach($Batch in $ParsedSql.Batches) { $SqlBatch=[pscustomobject][Ordered]@{ StartOffset = $Batch.StartOffset; StopOffset = $Batch.StartOffset+$Batch.FragmentLength; Length = $Batch.FragmentLength; StartColumn = $Batch.StartColumn; BatchId = $id; BlockType = 'Code'; Text = $s.Substring($Batch.StartOffset, $Batch.FragmentLength) } $SqlBatches+=$SqlBatch $id++ } $ScriptFrags = (Get-ParsedSql -ScriptPath $ScriptPath).ScriptTokenStream.where({$_.TokenType -eq 'MultilineComment'}) #If there are no comments to extract, we will skip the next section of code. if($ScriptFrags){ $Comments = @() $Comment = @() foreach($Frag in $ScriptFrags ) { $Comment=[pscustomobject][Ordered]@{ StartOffset = $Frag.Offset; StopOffset = $Frag.Offset+$Frag.Text.Length; Length = $Frag.Text.Length; StartColumn = $Frag.Column; CommentLocation = $null; BlockType = 'Comment'; Text = $Frag.Text } foreach($SqlBatch in $SqlBatches){ if($Comment.StartOffset -ge $SqlBatch.StartOffset -and $Comment.StartOffset -le $SqlBatch.StopOffset) {$Comment.CommentLocation = "Within SQL Batch $($SqlBatch.BatchId)"} else {if($Comment.CommentLocation -notlike '*Within*'){$Comment.CommentLocation = "Outside"}} } $Comments+=$Comment } } <################################################################################################# This is the basic product of Mulit-line Coments that are outside of Batches. Can you detect parameters in a test? #################################################################################################> if($ExtractCommentsInsideBatches){ $ExtractAllComments = $Comments } else { $ExtractAllComments = $Comments | Where-Object { $_.CommentLocation -eq 'Outside' } } $NotebookBlocks = $SqlBatches + $ExtractAllComments if($IncludeGaps -eq $false){ return $NotebookBlocks | Sort-Object StartOffset } else { if($NotebookBlocks.Count -eq 1 -and $NotebookBlocks.StopOffset -eq $s.Length){ return $NotebookBlocks | Sort-Object StartOffset} else { <################################################################################################# This What we do with the offset results to identify Gaps. #################################################################################################> $SqlBlocks = $NotebookBlocks | Sort-Object StartOffset $BlocksWitGaps = @() $Previous = @{StartOffset=0;StopOffset=0} foreach($SqlBlock in $SqlBlocks ) { $BlockOffsets=[ordered]@{ StartOffset = $SqlBlock.StartOffset; StopOffset = $SqlBlock.StopOffset; Length = $SqlBlock.Length; GapLength = [int] $SqlBlock.StartOffset-$Previous.StopOffset; PreviousStartOffset = $Previous.StartOffset; PreviousStopOffset = $Previous.StopOffset; CommentLocation = $SqlBlock.CommentLocation; BlockType = $SqlBlock.BlockType; GapText = IF($SqlBlock.StartOffset-$Previous.StopOffset -gt 1){[string] $s.Substring($Previous.StopOffset, ($SqlBlock.StartOffset-$Previous.StopOffset))}else {[string] ''}; Text = $SqlBlock.Text } $Previous=$BlockOffsets $BlocksWitGaps+=[pscustomobject] $BlockOffsets } <################################################################################################# This is an extra step to combine Gaps with Batches & Comments in a single structure. #################################################################################################> $AllBlocks = @() $GapOffsets = @() $Previous = @{StartOffset=0;StopOffset=0} if($BlocksWitGaps.Count -eq 1){$AllBlocks = @($SqlBlocks;[pscustomobject][Ordered]@{ StartOffset=0; StopOffset = $BlocksWitGaps.GapLength; Length = $BlocksWitGaps.GapLength; StartColumn = $null; BatchId=0; BlockType = 'Gap'; Text = $BlocksWitGaps.GapText})} else{ $AllBlocks = $SqlBlocks foreach($GapBlock in $BlocksWitGaps ) { $GapOffsets=[ordered]@{ StartOffset = $GapBlock.PreviousStopOffset; StopOffset = $GapBlock.StartOffset; Length = $GapBlock.GapLength; StartColumn = $null; CommentLocation = 'Between'; BlockType = 'Gap'; Text = $GapBlock.GapText } $Previous=$GapOffsets $AllBlocks+=if($GapOffsets.Length -gt 2){[pscustomobject] $GapOffsets} } } #$AllBlocks | Sort-Object StartOffset | ft -AutoSize -Wrap return $AllBlocks } } } function ConvertTo-SQLNoteBook { <# .Example ConvertTo-SQLNoteBook -InputFileName 'C:\temp\AdventureWorksMultiStatementSBatch.sql' -OutputNotebookName 'C:\temp\AdventureWorksMultiStatementSBatch.ipynb' #> param( $InputFileName, $OutputNotebookName ) New-SQLNotebook -NoteBookName $OutputNotebookName { $s = Get-Content -Raw ( Resolve-Path $InputFileName ) $AllNoteBlocks = Get-ParsedSqlOffsets -ScriptPath $InputFileName foreach($Block in $AllNoteBlocks | Sort-Object StartOffset ) { switch ($Block.BlockType) { 'Code' {$CodeBlock = $s.Substring($Block.StartOffset, $Block.Length) Write-Verbose "CODE - $($CodeBlock)" if($CodeBlock.Trim().length -gt 0){ Add-NotebookCode -code (-join $CodeBlock) } } 'Comment' {$TextBlock = $s.Substring($Block.StartOffset+2, $Block.Length-4) -replace ("\r\n", " `n ") Write-Verbose "COMMENT - $($TextBlock)" if($TextBlock.Trim().length -gt 0){ Add-NotebookMarkdown -markdown (-join $TextBlock) } } 'Gap' {$GapBlock = ($s.Substring($Block.StartOffset, $Block.Length) -replace ("\n", " `n ")).TrimStart().TrimEnd() Write-Verbose "COMMENT - $($GapBlock)" if($GapBlock.Trim().length -gt 0){ Add-NotebookMarkdown -markdown (-join $GapBlock) } } } } } } |