Install-Dynamics365Server.psm1

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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
function Install-Dynamics365Server {
    param (
        [Parameter(Mandatory=$true)]
        [string]
        $MediaDir,
        [Parameter(Mandatory=$true)]
        [string]
        $LicenseKey,
        [Parameter(Mandatory=$true)]
        [string]
        $InstallDir,
        [Parameter(Mandatory=$true)]
        [switch]
        $CreateDatabase,
        [Parameter(Mandatory=$true)]
        [string]
        $SqlServer,
        [Parameter(Mandatory=$true)]
        [string]
        $PrivUserGroup,
        [Parameter(Mandatory=$true)]
        [string]
        $SQLAccessGroup,
        [Parameter(Mandatory=$true)]
        [string]
        $UserGroup,
        [Parameter(Mandatory=$true)]
        [string]
        $ReportingGroup,
        [Parameter(Mandatory=$true)]
        [string]
        $PrivReportingGroup,
        [Parameter(Mandatory=$true)]
        [pscredential]
        $CrmServiceAccount,
        [Parameter(Mandatory=$true)]
        [pscredential]
        $DeploymentServiceAccount,
        [Parameter(Mandatory=$true)]
        [pscredential]
        $SandboxServiceAccount,
        [Parameter(Mandatory=$true)]
        [pscredential]
        $VSSWriterServiceAccount,
        [Parameter(Mandatory=$true)]
        [pscredential]
        $AsyncServiceAccount,
        [Parameter(Mandatory=$true)]
        [pscredential]
        $MonitoringServiceAccount,
        [Parameter(Mandatory=$true)]
        [switch]
        $CreateWebSite,
        [Parameter(Mandatory=$true)]
        [int]
        $WebSitePort,
        [Parameter(Mandatory=$true)]
        [string]
        $WebSiteUrl,
        [string]
        $IncomingExchangeServer,
        [Parameter(Mandatory=$true)]
        [string]
        $Organization,
        [Parameter(Mandatory=$true)]
        [string]
        $OrganizationUniqueName,
        [Parameter(Mandatory=$true)]
        [string]
        $BaseISOCurrencyCode,
        [Parameter(Mandatory=$true)]
        [string]
        $BaseCurrencyName,
        [Parameter(Mandatory=$true)]
        [string]
        $BaseCurrencySymbol,
        [Parameter(Mandatory=$true)]
        [int]
        $BaseCurrencyPrecision,
        [Parameter(Mandatory=$true)]
        [string]
        $OrganizationCollation,
        [Parameter(Mandatory=$true)]
        [string]
        $ReportingUrl,
        [switch]
        $SQM = $false,
        [switch]
        $MUOptin = $false,
        [switch]
        $Reboot = $false,
        [pscredential]
        $InstallAccount
    )
    $setupFilePath = "$mediaDir\SetupServer.exe";
    $fileVersion = ( Get-Command $setupFilePath ).FileVersionInfo.FileVersionRaw.ToString();
    Write-Host "Version of software to be installed: $fileVersion";
    $testScriptBlock = {
        try {
            Add-PSSnapin Microsoft.Crm.PowerShell -ErrorAction Ignore
            if ( Get-PSSnapin Microsoft.Crm.PowerShell -ErrorAction Ignore ) {
                $CrmOrganization = Get-CrmOrganization;
                $CrmOrganization.Version;
            } else {
                "Could not load Microsoft.Crm.PowerShell PSSnapin";
            }
        } catch {
            Write-Host "$(Get-Date) Caught an exception: $($_.Exception.Message)";
            $_.Exception.Message;
        }
    }
    if ( $installAccount )
    {
        $testResponse = Invoke-Command -ScriptBlock $testScriptBlock $env:COMPUTERNAME -Credential $installAccount -Authentication CredSSP;
    } else {
        $testResponse = Invoke-Command -ScriptBlock $testScriptBlock;
    }
    $productDetected = $null;
    if ( $testResponse.StartsWith( "9." ) -or $testResponse.StartsWith( "8." ) ) {
        $productDetected = $testResponse;
    }
    # Starting installation only when no Dynamics products is installed.
    if ( !$productDetected ) {
        $xml = [xml]"";
        $crmSetupElement = $xml.CreateElement( "CRMSetup" );
            $serverElement = $xml.CreateElement( "Server" );
                $patchElement = $xml.CreateElement( "Patch" );
                    $patchElement.SetAttribute( "Update", $false ) | Out-Null;
                $serverElement.AppendChild( $patchElement ) | Out-Null;
                $licenseKeyElement = $xml.CreateElement( "LicenseKey" );
                    $licenseKeyElement.InnerText = $licenseKey;
                $serverElement.AppendChild( $licenseKeyElement ) | Out-Null;
                $installDirElement = $xml.CreateElement( "InstallDir" );
                    $installDirElement.InnerText = $installDir;
                $serverElement.AppendChild( $installDirElement ) | Out-Null;
                $databaseElement = $xml.CreateElement( "Database" );
                    $databaseElement.SetAttribute( "create", $createDatabase ) | Out-Null;
                $serverElement.AppendChild( $databaseElement ) | Out-Null;
                $SQLServerElement = $xml.CreateElement( "SqlServer" );
                    $SQLServerElement.InnerText = $SQLServer;
                $serverElement.AppendChild( $SQLServerElement ) | Out-Null;
                $groupsElement = $xml.CreateElement( "Groups" );
                    $groupsElement.SetAttribute( "autogroupmanagementoff", $false ) | Out-Null;
                    $privUserGroupElement = $xml.CreateElement( "PrivUserGroup" );
                        $privUserGroupElement.InnerText = $privUserGroup;
                    $groupsElement.AppendChild( $privUserGroupElement ) | Out-Null;
                    $SQLAccessGroupElement = $xml.CreateElement( "SQLAccessGroup" );
                        $SQLAccessGroupElement.InnerText = $SQLAccessGroup;
                    $groupsElement.AppendChild( $SQLAccessGroupElement ) | Out-Null;
                    $userGroupElement = $xml.CreateElement( "UserGroup" );
                        $userGroupElement.InnerText = $userGroup;
                    $groupsElement.AppendChild( $userGroupElement ) | Out-Null;
                    $reportingGroupElement = $xml.CreateElement( "ReportingGroup" );
                        $reportingGroupElement.InnerText = $reportingGroup;
                    $groupsElement.AppendChild( $reportingGroupElement ) | Out-Null;
                    $privReportingGroupElement = $xml.CreateElement( "PrivReportingGroup" );
                        $privReportingGroupElement.InnerText = $privReportingGroup;
                    $groupsElement.AppendChild( $privReportingGroupElement ) | Out-Null;
                $serverElement.AppendChild( $groupsElement ) | Out-Null;
                $CRMServiceAccountElement = $xml.CreateElement( "CrmServiceAccount" );
                    $CRMServiceAccountElement.SetAttribute( "type", "DomainUser" ) | Out-Null;
                    $serviceAccountLoginElement = $xml.CreateElement( "ServiceAccountLogin" );
                        $serviceAccountLoginElement.InnerText = $CRMServiceAccount.UserName;
                    $CRMServiceAccountElement.AppendChild( $serviceAccountLoginElement ) | Out-Null;
                    $serviceAccountPasswordElement = $xml.CreateElement( "ServiceAccountPassword" );
                        $serviceAccountPasswordElement.InnerText = $CRMServiceAccount.GetNetworkCredential().Password;
                    $CRMServiceAccountElement.AppendChild( $serviceAccountPasswordElement ) | Out-Null;
                $serverElement.AppendChild( $CRMServiceAccountElement ) | Out-Null;
                $deploymentServiceAccountElement = $xml.CreateElement( "DeploymentServiceAccount" );
                    $deploymentServiceAccountElement.SetAttribute( "type", "DomainUser" ) | Out-Null;
                    $serviceAccountLoginElement = $xml.CreateElement( "ServiceAccountLogin" );
                        $serviceAccountLoginElement.InnerText = $deploymentServiceAccount.UserName;
                    $deploymentServiceAccountElement.AppendChild( $serviceAccountLoginElement ) | Out-Null;
                    $serviceAccountPasswordElement = $xml.CreateElement( "ServiceAccountPassword" );
                        $serviceAccountPasswordElement.InnerText = $deploymentServiceAccount.GetNetworkCredential().Password;
                    $deploymentServiceAccountElement.AppendChild( $serviceAccountPasswordElement ) | Out-Null;
                $serverElement.AppendChild( $deploymentServiceAccountElement ) | Out-Null;
                $sandboxServiceAccountElement = $xml.CreateElement( "SandboxServiceAccount" );
                    $sandboxServiceAccountElement.SetAttribute( "type", "DomainUser" ) | Out-Null;
                    $serviceAccountLoginElement = $xml.CreateElement( "ServiceAccountLogin" );
                        $serviceAccountLoginElement.InnerText = $sandboxServiceAccount.UserName;
                    $sandboxServiceAccountElement.AppendChild( $serviceAccountLoginElement ) | Out-Null;
                    $serviceAccountPasswordElement = $xml.CreateElement( "ServiceAccountPassword" );
                        $serviceAccountPasswordElement.InnerText = $sandboxServiceAccount.GetNetworkCredential().Password;
                    $sandboxServiceAccountElement.AppendChild( $serviceAccountPasswordElement ) | Out-Null;
                $serverElement.AppendChild( $sandboxServiceAccountElement ) | Out-Null;
                $VSSWriterServiceAccountElement = $xml.CreateElement( "VSSWriterServiceAccount" );
                    $VSSWriterServiceAccountElement.SetAttribute( "type", "DomainUser" ) | Out-Null;
                    $serviceAccountLoginElement = $xml.CreateElement( "ServiceAccountLogin" );
                        $serviceAccountLoginElement.InnerText = $VSSWriterServiceAccount.UserName;
                    $VSSWriterServiceAccountElement.AppendChild( $serviceAccountLoginElement ) | Out-Null;
                    $serviceAccountPasswordElement = $xml.CreateElement( "ServiceAccountPassword" );
                        $serviceAccountPasswordElement.InnerText = $VSSWriterServiceAccount.GetNetworkCredential().Password;
                    $VSSWriterServiceAccountElement.AppendChild( $serviceAccountPasswordElement ) | Out-Null;
                $serverElement.AppendChild( $VSSWriterServiceAccountElement ) | Out-Null;
                $asyncServiceAccountElement = $xml.CreateElement( "AsyncServiceAccount" );
                    $asyncServiceAccountElement.SetAttribute( "type", "DomainUser" ) | Out-Null;
                    $serviceAccountLoginElement = $xml.CreateElement( "ServiceAccountLogin" );
                        $serviceAccountLoginElement.InnerText = $asyncServiceAccount.UserName;
                    $asyncServiceAccountElement.AppendChild( $serviceAccountLoginElement ) | Out-Null;
                    $serviceAccountPasswordElement = $xml.CreateElement( "ServiceAccountPassword" );
                        $serviceAccountPasswordElement.InnerText = $asyncServiceAccount.GetNetworkCredential().Password;
                    $asyncServiceAccountElement.AppendChild( $serviceAccountPasswordElement ) | Out-Null;
                $serverElement.AppendChild( $asyncServiceAccountElement ) | Out-Null;
                $monitoringServiceAccountElement = $xml.CreateElement( "MonitoringServiceAccount" );
                    $monitoringServiceAccountElement.SetAttribute( "type", "DomainUser" ) | Out-Null;
                    $serviceAccountLoginElement = $xml.CreateElement( "ServiceAccountLogin" );
                        $serviceAccountLoginElement.InnerText = $monitoringServiceAccount.UserName;
                    $monitoringServiceAccountElement.AppendChild( $serviceAccountLoginElement ) | Out-Null;
                    $serviceAccountPasswordElement = $xml.CreateElement( "ServiceAccountPassword" );
                        $serviceAccountPasswordElement.InnerText = $monitoringServiceAccount.GetNetworkCredential().Password;
                    $monitoringServiceAccountElement.AppendChild( $serviceAccountPasswordElement ) | Out-Null;
                $serverElement.AppendChild( $monitoringServiceAccountElement ) | Out-Null;
                $webSiteUrlElement = $xml.CreateElement( "WebsiteUrl" );
                    $webSiteUrlElement.SetAttribute( "create", $createWebSite ) | Out-Null;
                    $webSiteUrlElement.SetAttribute( "port", $webSitePort ) | Out-Null;
                    $webSiteUrlElement.InnerText = $webSiteUrl;
                $serverElement.AppendChild( $webSiteUrlElement ) | Out-Null;
                $emailElement = $xml.CreateElement( "Email" );
                    $incomingExchangeServerElement = $xml.CreateElement( "IncomingExchangeServer" );
                        $incomingExchangeServerElement.SetAttribute( "name", $incomingExchangeServer ) | Out-Null;
                    $emailElement.AppendChild( $incomingExchangeServerElement ) | Out-Null;
                $serverElement.AppendChild( $emailElement ) | Out-Null;
                $organizationUniqueNameElement = $xml.CreateElement( "OrganizationUniqueName" );
                    $organizationUniqueNameElement.InnerText = $organizationUniqueName;
                $serverElement.AppendChild( $organizationUniqueNameElement ) | Out-Null;
                $organizationElement = $xml.CreateElement( "Organization" );
                    $organizationElement.InnerText = $organization;
                $serverElement.AppendChild( $organizationElement ) | Out-Null;
                $baseCurrencyElement = $xml.CreateElement( "basecurrency" );
                    $baseCurrencyElement.SetAttribute( "isocurrencycode", $baseISOCurrencyCode ) | Out-Null;
                    $baseCurrencyElement.SetAttribute( "currencyname", $baseCurrencyName ) | Out-Null;
                    $baseCurrencyElement.SetAttribute( "currencysymbol", $baseCurrencySymbol ) | Out-Null;
                    $baseCurrencyElement.SetAttribute( "currencyprecision", $baseCurrencyPrecision ) | Out-Null;
                $serverElement.AppendChild( $baseCurrencyElement ) | Out-Null;
                $organizationCollationElement = $xml.CreateElement( "OrganizationCollation" );
                    $organizationCollationElement.InnerText = $organizationCollation;
                $serverElement.AppendChild( $organizationCollationElement ) | Out-Null;
                $reportingElement = $xml.CreateElement( "Reporting" );
                    $reportingElement.SetAttribute( "URL", $ReportingUrl ) | Out-Null;
                $serverElement.AppendChild( $reportingElement ) | Out-Null;
                $SQMElement = $xml.CreateElement( "SQM" );
                    $SQMElement.SetAttribute( "optin", $SQM ) | Out-Null;
                $serverElement.AppendChild( $SQMElement ) | Out-Null;
                $MUOptinElement = $xml.CreateElement( "muoptin" );
                    $MUOptinElement.SetAttribute( "optin", $MUOptin ) | Out-Null;
                $serverElement.AppendChild( $MUOptinElement ) | Out-Null;
                $remoteInstallElement = $xml.CreateElement( "remoteinstall" );
                    $remoteInstallElement.InnerText = $true;
                $serverElement.AppendChild( $remoteInstallElement ) | Out-Null;
                $rebootElement = $xml.CreateElement( "Reboot" );
                    $rebootElement.InnerText = $reboot;
                $serverElement.AppendChild( $rebootElement ) | Out-Null;
                $launchReportingExtensionsSetupElement = $xml.CreateElement( "LaunchReportingExtensionsSetup" );
                    $launchReportingExtensionsSetupElement.InnerText = $true;
                $serverElement.AppendChild( $launchReportingExtensionsSetupElement ) | Out-Null;
            $crmSetupElement.AppendChild( $serverElement ) | Out-Null;
        $xml.AppendChild( $crmSetupElement ) | Out-Null;

        $stringWriter = New-Object System.IO.StringWriter;
        $xmlWriter = New-Object System.Xml.XmlTextWriter $stringWriter;
        $xmlWriter.Formatting = "indented";
        $xml.WriteTo( $xmlWriter );
        $xmlWriter.Flush();
        $stringWriter.Flush();

        $localInstallationScriptBlock = {
            param( $setupFilePath, $xmlConfig )
            $tempFileName = [guid]::NewGuid().Guid;
            $tempFilePath = "$env:Temp\$tempFileName.xml";
            Write-Host "$(Get-Date) Saving configuration temporary to $tempFilePath";
            Set-Content -Path $tempFilePath -Value $xmlConfig;
            Write-Host "$(Get-Date) Starting $setupFilePath";
            $timeStamp = ( Get-Date -Format u ).Replace(" ","-").Replace(":","-");
            $logFileName = "$env:Temp\CRMInstallationLog_$timeStamp.txt";
            $installCrmScript = {
                param( $setupFilePath, $tempFilePath, $logFileName );
                Write-Host "Start-Process '$setupFilePath' -ArgumentList '/Q /config $tempFilePath /L $logFileName' -Wait;";
                Start-Process "$setupFilePath" -ArgumentList "/Q /config $tempFilePath /L $logFileName" -Wait;
            }
            $job = Start-Job -ScriptBlock $installCrmScript -ArgumentList $setupFilePath, $tempFilePath, $logFileName;
            Write-Host "$(Get-Date) Started installation job, log will be saved in $logFileName";
            While ( $job.State -ne "Completed" )
            {
                Write-Host "$(Get-Date) Waiting until CRM installation job is done";
                Sleep 60;
            }
            Write-Host "$(Get-Date) Job is complete, output:";
            Write-Output ( Receive-Job $job );
            Remove-Job $job;
            Remove-Item $tempFilePath;
        }
        if ( $installAccount )
        {
            Invoke-Command -ScriptBlock $localInstallationScriptBlock $env:COMPUTERNAME -Credential $installAccount -Authentication CredSSP -ArgumentList $setupFilePath, $stringWriter.ToString();
        } else {
            Invoke-Command -ScriptBlock $localInstallationScriptBlock -ArgumentList $setupFilePath, $stringWriter.ToString();
        }
        $testScriptBlock = {
            try {
                Add-PSSnapin Microsoft.Crm.PowerShell -ErrorAction Ignore
                if ( Get-PSSnapin Microsoft.Crm.PowerShell -ErrorAction Ignore ) {
                    $CrmOrganization = Get-CrmOrganization;
                    $CrmOrganization.Version;
                } else {
                    "Could not load Microsoft.Crm.PowerShell PSSnapin";
                }
            } catch {
                $_.Exception.Message;
            }
        }
        if ( $installAccount )
        {
            $testResponse = Invoke-Command -ScriptBlock $testScriptBlock $env:COMPUTERNAME -Credential $installAccount -Authentication CredSSP;
        } else {
            $testResponse = Invoke-Command -ScriptBlock $testScriptBlock;
        }
        if ( $testResponse -eq $fileVersion ) {
            Write-Host "Installation is finished and verified successfully";
        } else {
            Write-Host "Installation job finished but the product is still not installed. Current product version installed is '$testResponse'";
            Throw "Installation job finished but the product is still not installed. Current product version installed is '$testResponse'";
        }
    } else {
        Write-Host "Product version '$testResponse' is already installed, skipping"
    }
}