Bacpac/Restore-DatabasesInNavContainer.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<#
 .Synopsis
  Restore databases in a NAV/BC Container from .bak files
 .Description
  If the Container is multi-tenant, this command will restore an app.bak and a number of tenant databases
  If the Container is single-tenant, this command will restore one .bak file called database.bak.
 .Parameter containerName
  Name of the container in which you want to restore databases
 .Parameter bakFolder
  The folder to which the bak files are exported (default is the container folder c:\programdata\navcontainerhelper\extensions\<containername>)
 .Parameter tenant
  The tenant database(s) to restore, only applies to multi-tenant containers. Omit to restore all tenants
 .Example
  Restore-DatabasesInNavContainer -containerName test
 .Example
  Restore-DatabasesInNavContainer -containerName test -tenant @("default")
 .Example
  Restore-DatabasesInBCContainer -containerName test -bakFile C:\ProgramData\NavContainerHelper\mydb.bak -databaseFolder "c:\databases\mydb"
#>

function Restore-DatabasesInNavContainer {
    Param(
        [string] $containerName = "navserver", 
        [string] $bakFolder = "",
        [string] $bakFile = "",
        [string] $databaseName = "",
        [string[]] $tenant,
        [Parameter(Mandatory=$false)]
        [string] $databaseFolder = "c:\databases",
        [int] $sqlTimeout = 300
    )

    $containerBakFile = ""
    $containerBakFolder = ""

    if ($bakFile) {
        if ($bakFolder) {
            throw "You cannot specify bakFolder when you specify bakFile"
        }
        if ($tenant) {
            throw "You cannot specify tenant when you specify bakFile"
        }
        $containerBakFile = Get-NavContainerPath -containerName $containerName -path $bakFile -throw
        if (-not $databaseName) {
            $databaseName = [System.IO.Path]::GetFileNameWithoutExtension($bakFile)
        }
    }
    elseif ($databaseName) {
        throw "You need to specify bakFile when you specify databaseName"
    }
    else {
        $containerFolder = Join-Path $ExtensionsFolder $containerName
        if ("$bakFolder" -eq "") {
            $bakFolder = $containerFolder
        }
        elseif (!$bakFolder.Contains('\')) {
            $navversion = Get-NavContainerNavversion -containerOrImageName $containerName
            if ((Invoke-ScriptInNavContainer -containerName $containerName -scriptblock { $env:IsBcSandbox }) -eq "Y") {
                $folderPrefix = "sandbox"
            }
            else {
                $folderPrefix = "onprem"
            }
            $bakFolder = Join-Path $containerHelperFolder "$folderPrefix-$NavVersion-bakFolders\$bakFolder"
        }
        $containerBakFolder = Get-NavContainerPath -containerName $containerName -path $bakFolder -throw
    }

    Invoke-ScriptInBCContainer -containerName $containerName -scriptblock { Param($bakFolder, $bakFile, $databaseName, $tenant, $databaseFolder, $sqlTimeout)

        function Restore {
            Param (
                [string] $databaseServer,
                [string] $databaseInstance,
                [string] $databaseName,
                [string] $bakFile,
                [string] $databaseFolder,
                [int] $sqlTimeout
            )
            if (!(Test-Path -Path $bakFile -PathType Leaf)) {
                throw "Database backup $bakFile not found"
            }
            if (Test-NavDatabase -DatabaseServer $databaseServer `
                                 -DatabaseInstance $databaseInstance `
                                 -DatabaseName $databaseName) {

                Remove-NavDatabase -DatabaseServer $databaseServer `
                                   -DatabaseInstance $databaseInstance `
                                   -DatabaseName $databaseName
            }
        
            Write-Host "Restoring $bakFile to $databaseName"
            New-NAVDatabase -DatabaseServer $databaseServer `
                            -DatabaseInstance $databaseInstance `
                            -DatabaseName $databaseName `
                            -FilePath $bakFile `
                            -DestinationPath $databaseFolder `
                            -Timeout $SqlTimeout | Out-Null
        }

        $customConfigFile = Join-Path (Get-Item "C:\Program Files\Microsoft Dynamics NAV\*\Service").FullName "CustomSettings.config"
        [xml]$customConfig = [System.IO.File]::ReadAllText($customConfigFile)
        $multitenant = ($customConfig.SelectSingleNode("//appSettings/add[@key='Multitenant']").Value -eq "true")
        $databaseServer = $customConfig.SelectSingleNode("//appSettings/add[@key='DatabaseServer']").Value
        $databaseInstance = $customConfig.SelectSingleNode("//appSettings/add[@key='DatabaseInstance']").Value

        if ($bakFile) {
            Restore -databaseServer $databaseServer -databaseInstance $databaseInstance -databaseName $DatabaseName -bakFile $bakFile -databaseFolder $databaseFolder -sqlTimeout $sqlTimeout
        }
        else {
            $databaseName = $customConfig.SelectSingleNode("//appSettings/add[@key='DatabaseName']").Value
    
            if ($multitenant -and !($tenant)) {
                $tenant = @(get-navtenant $serverInstance | % { $_.Id }) + "tenant"
            }
    
            Set-NavServerInstance -ServerInstance $serverInstance -stop
    
            if ($multitenant) {
                Restore -databaseServer $databaseServer -databaseInstance $databaseInstance -databaseName $DatabaseName -bakFile (Join-Path $bakFolder "app.bak") -databaseFolder $databaseFolder -sqlTimeout $sqlTimeout
                $tenant | ForEach-Object {
                    Restore -databaseServer $databaseServer -databaseInstance $databaseInstance -databaseName $_ -bakFile (Join-Path $bakFolder "$_.bak") -databaseFolder $databaseFolder -sqlTimeout $sqlTimeout
                }
            } else {
                Restore -databaseServer $databaseServer -databaseInstance $databaseInstance -databaseName $DatabaseName -bakFile (Join-Path $bakFolder "database.bak") -databaseFolder $databaseFolder -sqlTimeout $sqlTimeout
            }
    
            Set-NavServerInstance -ServerInstance $serverInstance -start
        }
    
    } -argumentList $containerBakFolder, $containerBakFile, $databaseName, $tenant, $databaseFolder, $sqlTimeout

}
Set-Alias -Name Restore-DatabasesInBCContainer -Value Restore-DatabasesInNavContainer
Export-ModuleMember -Function Restore-DatabasesInNavContainer -Alias Restore-DatabasesInBCContainer