Skip to content

Commit

Permalink
Merge pull request #817 from FH-Inway/747-update-sqlpackage
Browse files Browse the repository at this point in the history
Update Invoke-D365InstallSqlPackage to install latest version of SQLPackage
  • Loading branch information
Splaxi authored May 2, 2024
2 parents 7be7523 + 7a64cbc commit c15d1fe
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 150 deletions.
57 changes: 47 additions & 10 deletions d365fo.tools/bin/d365fo.tools-index.json

Large diffs are not rendered by default.

71 changes: 34 additions & 37 deletions d365fo.tools/functions/invoke-d365installsqlpackage.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,84 +4,75 @@
Download SqlPackage.exe to your machine
.DESCRIPTION
Download and extract the DotNet/.NET core x64 edition of the SqlPackage.exe to your machine
It parses the raw html page and tries to extract the latest download link.
As of 12th April 2022, no .NET Core link is available on the download page. The cmdlet will always use the Url parameter.
Download and extract SqlPackage.exe to your machine.
.PARAMETER Path
Path to where you want the SqlPackage to be extracted to
Default value is: "C:\temp\d365fo.tools\SqlPackage\SqlPackage.exe"
.PARAMETER SkipExtractFromPage
Instruct the cmdlet to skip trying to parse the download page and to rely on the Url parameter only
.PARAMETER Latest
Overrides the Url parameter and uses the latest download URL provided by the evergreen link https://aka.ms/sqlpackage-windows
.PARAMETER Url
Url/Uri to where the latest SqlPackage download is located
Url/Uri to where the SqlPackage download is located
The default value is for version 162.2.111.2 as of writing.
The default value is for v19.1 (16.0.6161.0) as of writing. This is the last version of SqlPackage based on .NET Core.
According to the Microsoft documentation, a .NET Core version of SqlPackage should be used.
https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/database/import-database
Further discussion can be found here: https://github.com/d365collaborative/d365fo.tools/issues/708
Further discussion can be found here: https://github.com/d365collaborative/d365fo.tools/discussions/816
.EXAMPLE
PS C:\> Invoke-D365InstallSqlPackage
This will download and extract the latest SqlPackage.exe.
This will download and extract SqlPackage.exe.
It will use the default value for the Path parameter, for where to save the SqlPackage.exe.
It will try to extract the latest download URL from the RAW html page.
It will update the path for the SqlPackage.exe in configuration.
.EXAMPLE
PS C:\> Invoke-D365InstallSqlPackage -Path "C:\temp\SqlPackage"
This will download and extract the latest SqlPackage.exe.
It will try to extract the latest download URL from the RAW html page.
This will download and extract SqlPackage.exe.
It will save the SqlPackage.exe to "C:\temp\SqlPackage".
It will update the path for the SqlPackage.exe in configuration.
.EXAMPLE
PS C:\> Invoke-D365InstallSqlPackage -SkipExtractFromPage
PS C:\> Invoke-D365InstallSqlPackage -Latest
This will download and extract the latest SqlPackage.exe.
It will rely on the Url parameter to based the download from.
It will use the default value of the Url parameter.
It will use https://aka.ms/sqlpackage-windows as the download URL.
It will update the path for the SqlPackage.exe in configuration.
.EXAMPLE
PS C:\> Invoke-D365InstallSqlPackage -SkipExtractFromPage -Url "https://go.microsoft.com/fwlink/?linkid=3030303"
PS C:\> Invoke-D365InstallSqlPackage -Url "https://go.microsoft.com/fwlink/?linkid=3030303"
This will download and extract the latest SqlPackage.exe.
It will rely on the Url parameter to based the download from.
This will download and extract SqlPackage.exe.
It will rely on the Url parameter to base the download on.
It will use the "https://go.microsoft.com/fwlink/?linkid=3030303" as value for the Url parameter.
It will update the path for the SqlPackage.exe in configuration.
.NOTES
Author: Mötz Jensen (@Splaxi)
Author: Florian Hopfner (@FH-Inway)
#>

function Invoke-D365InstallSqlPackage {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
[CmdletBinding()]
[CmdletBinding(DefaultParameterSetName = 'ImportUrl')]
[OutputType()]
param (
[Parameter(ParameterSetName = 'ImportUrl')]
[Parameter(ParameterSetName = 'ImportLatest')]
[string] $Path = "C:\temp\d365fo.tools\SqlPackage",

[switch] $SkipExtractFromPage,

[string] $Url = "https://go.microsoft.com/fwlink/?linkid=2196334"

[Parameter(ParameterSetName = 'ImportLatest')]
[switch] $Latest,

[Parameter(ParameterSetName = 'ImportUrl')]
[string] $Url = "https://go.microsoft.com/fwlink/?linkid=2261576"
)

if (-not $SkipExtractFromPage) {
$content = (Invoke-WebRequest -Uri "https://learn.microsoft.com/en-us/sql/tools/sqlpackage-download" -UseBasicParsing).content
$res = $content -match '<td.*>Windows .NET Core<.*/td>\s*<td.*><a href="(https://.*)" .*'

if ($res) {
$Url = ([string]$Matches[1]).Trim()
}
else {
Write-PSFMessage -Level Host -Message "Parsing the web page didn't succeed. Will fall back to the download url." -Target "https://learn.microsoft.com/en-us/sql/tools/sqlpackage-download"
}
if ($Latest) {
$Url = "https://aka.ms/sqlpackage-windows"
}

$sqlPackageFolder = $Path
Expand All @@ -107,5 +98,11 @@ function Invoke-D365InstallSqlPackage {
$tempExtractPath | Remove-Item -Force -Recurse
$downloadPath | Remove-Item -Force -Recurse

Set-D365SqlPackagePath -Path $(Join-Path -Path $Path -ChildPath "SqlPackage.exe")
$SqlPackagePath = Join-Path -Path $Path -ChildPath "SqlPackage.exe"
Set-D365SqlPackagePath -Path $SqlPackagePath

$result = Invoke-Process -Path $SqlPackagePath -Params "/Version"
$version = $result.stdout -replace "`r`n", ""

Write-PSFMessage -Level Host -Message "SqlPackage.exe version $version has been downloaded and extracted to $SqlPackagePath"
}
8 changes: 8 additions & 0 deletions d365fo.tools/internal/functions/invoke-process.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,12 @@ function Invoke-Process {
}

Invoke-TimeSignal -End

if (-not $ShowOriginalProgress) {
[PSCustomObject]@{
stdout = $stdout
stderr = $stderr
ExitCode = $p.ExitCode
}
}
}
95 changes: 49 additions & 46 deletions d365fo.tools/internal/functions/invoke-sqlpackage.ps1
Original file line number Diff line number Diff line change
@@ -1,114 +1,113 @@

<#
<#
.SYNOPSIS
Invoke the sqlpackage executable
.DESCRIPTION
Invoke the sqlpackage executable and pass the necessary parameters to it
.PARAMETER Action
Can either be import or export
.PARAMETER DatabaseServer
The name of the database server
If on-premises or classic SQL Server, use either short name og Fully Qualified Domain Name (FQDN).
If Azure use the full address to the database server, e.g. server.database.windows.net
.PARAMETER DatabaseName
The name of the database
.PARAMETER SqlUser
The login name for the SQL Server instance
.PARAMETER SqlPwd
The password for the SQL Server user
.PARAMETER TrustedConnection
Should the sqlpackage work with TrustedConnection or not
.PARAMETER FilePath
Path to the file, used for either import or export
.PARAMETER Properties
Array of all the properties that needs to be parsed to the sqlpackage.exe
.PARAMETER DiagnosticFile
Path to where you want the SqlPackage to output a diagnostics file to assist you in troubleshooting
.PARAMETER ModelFile
Path to the model file that you want the SqlPackage.exe to use instead the one being part of the bacpac file
This is used to override SQL Server options, like collation and etc
.PARAMETER MaxParallelism
Sets SqlPackage.exe's degree of parallelism for concurrent operations running against a database
The default value is 8
.PARAMETER PublishFile
Path to the profile / publish xml file that contains all the advanced configuration instructions for the SqlPackage
Used only in combination with the Publish action
.PARAMETER LogPath
The path where the log file(s) will be saved
.PARAMETER ShowOriginalProgress
Instruct the cmdlet to show the standard output in the console
Default is $false which will silence the standard output
.PARAMETER OutputCommandOnly
Instruct the cmdlet to only output the command that you would have to execute by hand
Will include full path to the executable and the needed parameters based on your selection
.PARAMETER EnableException
This parameters disables user-friendly warnings and enables the throwing of exceptions
This is less user friendly, but allows catching exceptions in calling scripts
.EXAMPLE
PS C:\> $BaseParams = @{
DatabaseServer = $DatabaseServer
DatabaseName = $DatabaseName
SqlUser = $SqlUser
SqlPwd = $SqlPwd
}
PS C:\> $ImportParams = @{
Action = "import"
FilePath = $BacpacFile
}
PS C:\> Invoke-SqlPackage @BaseParams @ImportParams
This will start the sqlpackage.exe file and pass all the needed parameters.
.NOTES
Author: Mötz Jensen (@splaxi)
#>
function Invoke-SqlPackage {
[CmdletBinding()]
[OutputType([System.Boolean])]
param (
[ValidateSet("Import", "Export", "Publish")]
[string] $Action,

[string] $DatabaseServer,

[string] $DatabaseName,

[string] $SqlUser,

[string] $SqlPwd,

[string] $TrustedConnection,

[string] $FilePath,

[string[]] $Properties,

[string] $DiagnosticFile,
Expand All @@ -128,7 +127,7 @@ function Invoke-SqlPackage {

[switch] $EnableException
)

$executable = $Script:SqlPackagePath

Invoke-TimeSignal -Start
Expand Down Expand Up @@ -161,12 +160,12 @@ function Invoke-SqlPackage {
$null = $Params.Add("/SourceTrustServerCertificate:True")
$null = $Params.Add("/TargetFile:`"$FilePath`"")
$null = $Params.Add("/Properties:CommandTimeout=0")

if (!$UseTrustedConnection) {
$null = $Params.Add("/SourceUser:$SqlUser")
$null = $Params.Add("/SourcePassword:$SqlPwd")
}

Remove-Item -Path $FilePath -ErrorAction SilentlyContinue -Force
}
elseif ($Action -eq "import") {
Expand All @@ -176,7 +175,7 @@ function Invoke-SqlPackage {
$null = $Params.Add("/TargetTrustServerCertificate:True")
$null = $Params.Add("/SourceFile:`"$FilePath`"")
$null = $Params.Add("/Properties:CommandTimeout=0")

if (!$UseTrustedConnection) {
$null = $Params.Add("/TargetUser:$SqlUser")
$null = $Params.Add("/TargetPassword:$SqlPwd")
Expand All @@ -189,7 +188,7 @@ function Invoke-SqlPackage {
$Params.Add("/TargetTrustServerCertificate:True") > $null
$Params.Add("/SourceFile:`"$FilePath`"") > $null
$Params.Add("/Properties:CommandTimeout=0") > $null

if (-not $UseTrustedConnection) {
$Params.Add("/TargetUser:$SqlUser") > $null
$Params.Add("/TargetPassword:$SqlPwd") > $null
Expand All @@ -208,7 +207,7 @@ function Invoke-SqlPackage {
$Params.Add("/Diagnostics:true") > $null
$Params.Add("/DiagnosticsFile:`"$DiagnosticFile`"") > $null
}

if ($ModelFile) {
$Params.Add("/ModelFilePath:`"$ModelFile`"") > $null
}
Expand All @@ -217,8 +216,12 @@ function Invoke-SqlPackage {
$Params.Add("/MaxParallelism:$MaxParallelism") > $null
}

$result = Invoke-Process -Path $executable -Params "/Version"
$version = $result.stdout -replace "`r`n", ""
Write-PSFMessage -Level Verbose -Message "Using SQLPackage version $version"

Invoke-Process -Executable $executable -Params $params -ShowOriginalProgress:$ShowOriginalProgress -OutputCommandOnly:$OutputCommandOnly -LogPath $LogPath

if (Test-PSFFunctionInterrupt) {
Write-PSFMessage -Level Critical -Message "The SqlPackage.exe exited with an error."
Stop-PSFFunction -Message "Stopping because of errors." -StepsUpward 1
Expand Down
Loading

0 comments on commit c15d1fe

Please sign in to comment.