functions/Set-D365LBDOptions.ps1
function Set-D365LBDOptions { <# .SYNOPSIS Uses switches to set different deployment options created for expanding the pre and post deployment scripts. .DESCRIPTION Uses switches to set different deployment options created for expanding the pre and post deployment scripts. Recommend: Run multiple times for each task then the last run run with the teams communication. .EXAMPLE $config = Get-D365Config Set-D365LBDOptions -RemoveMR -predeployment -config $config Prevents the installation of Management reporter in the predeployment stage .EXAMPLE $config = Get-D365Config Set-D365LBDOptions -predeployment -enableuserid 'stefan' -config $config Enables user stefan in the predeployment stage .EXAMPLE $config = Get-D365Config Set-D365LBDOptions -predeployment -OtherTaskName 'TalkedToMyself' -OtherTaskStatus 'Success' -config $config Adds a custom task and status to the predeployment list for communication .EXAMPLE $config = Get-D365Config Set-D365LBDOptions -postdeployment -MSTEAMSCustomStatus 'Deployment Finished' -MSTeamsURI 'https://fake.outlook.com/webhook/fakeurl/123123' -MSTeamsBuildName '2021.03.04.01' -MSTeamsExtraDetails 'Web Search' -MSTeamsExtraDetailsURI 'https://google.com' -config $config Custom status of deployment finished and added an extra field called Web Search with a link to google. Also says the Build name as '2021.03.04.01' (recommend making a build name related to the config) #> [alias("Set-D365Options")] [CmdletBinding()] param ( [PSFComputer]$ComputerName = "$env:COMPUTERNAME", [Parameter(ParameterSetName = 'Config', ValueFromPipeline = $True)] [psobject]$Config, [switch]$PreDeployment, [switch]$PostDeployment, [switch]$RemoveMR, [switch]$MaintenanceModeOn, [switch]$MaintenanceModeOff, [string]$MSTeamsURI, [string]$MSTeamsExtraDetailsURI, [string]$MSTeamsExtraDetails, [string]$MSTeamsBuildName, [string]$MSTeamsCustomStatus, [string]$SQLQueryToRun, [string]$EnableUserid, [string]$DisableUserid, [string]$OtherTaskName, [string]$OtherTaskStatus ) BEGIN { } PROCESS { if (!$Config -or $Config.OrchestratorServerNames.Count -eq 0) { Write-PSFMessage -Level VeryVerbose -Message "Config not defined or Config is invalid. Trying to Get new config using $ComputerName" $Config = Get-D365LBDConfig -ComputerName $ComputerName -HighLevelOnly } if ($PreDeployment) { Write-PSFMessage -Level Verbose -Message "PreDeployment Selected" $filenameprename = "PREDeployment" } if ($PostDeployment) { Write-PSFMessage -Level Verbose -Message "PostDeployment Selected" $filenameprename = "PostDeployment" } if ($Config) { $agentsharelocation = $Config.AgentShareLocation $AXDatabaseServer = $Config.AXDatabaseServer $AXDatabaseName = $Config.AXDatabaseName $LCSEnvironmentName = $Config.LCSEnvironmentName $clienturl = $Config.clienturl $LastRunbookTaskId = $Config.LastRunbookTaskId if (!$AXDatabaseServer) { $AXDatabaseServer = $config.databaseclusterservernames | select -First 1 if (!$AXDatabaseServer) { $AXDatabaseServer = $config.OrchDatabaseServer } } } if ((Test-Path $agentsharelocation\scripts\D365FOLBDAdmin) -eq $false) { new-item -path "$agentsharelocation\scripts\" -Name "D365FOLBDAdmin" -ItemType "directory" } if ($null -eq $LastRunbookTaskId) { $norunbooktaskid = get-date -Format MMddyy if ((Test-Path $agentsharelocation\scripts\D365FOLBDAdmin\$filenameprename$norunbooktaskid.xml) -eq $false) { #$newfile = New-Item $agentsharelocation -path $agentsharelocation\scripts\D365FOLBDAdmin -Name "$filenameprename$norunbooktaskid.xml" @{} | Export-Clixml "$agentsharelocation\scripts\D365FOLBDAdmin\$filenameprename$norunbooktaskid.xml" } else { Write-PSFMessage -Level VeryVerbose -Message "$filenameprename$LastRunbookTaskId.xml already exists" } } else { if ((Test-Path $agentsharelocation\scripts\D365FOLBDAdmin\$filenameprename$LastRunbookTaskId.xml) -eq $false) { $newfile = New-Item -path $agentsharelocation\scripts\D365FOLBDAdmin -Name "$filenameprename$LastRunbookTaskId.xml" @{} | Export-Clixml "$agentsharelocation\scripts\D365FOLBDAdmin\$filenameprename$LastRunbookTaskId.xml" $CLIXML = Import-Clixml "$agentsharelocation\scripts\D365FOLBDAdmin\$filenameprename$LastRunbookTaskId.xml" } else { Write-PSFMessage -Level VeryVerbose -Message "$agentsharelocation\scripts\D365FOLBDAdmin\$filenameprename$LastRunbookTaskId.xml already exists" $newfile = Get-ChildItem $agentsharelocation\scripts\D365FOLBDAdmin\$filenameprename$LastRunbookTaskId.xml $CLIXML = Import-Clixml "$agentsharelocation\scripts\D365FOLBDAdmin\$filenameprename$LastRunbookTaskId.xml" } } if ($OtherTaskName) { if (!$OtherTaskStatus) { $OtherTaskStatus = "Success" } $CLIXML += @{"$OtherTaskName" = "$OtherTaskStatus" } } if ($RemoveMR) { Write-PSFMessage -Level Verbose -Message "Attempting to Remove MR" if ($PreDeployment -eq $True) { $JsonLocation = Get-ChildItem $AgentShareLocation\wp\*\StandaloneSetup-*\SetupModules.json | Sort-Object { $_.CreationTime } -Descending | Select-Object -First 1 $JsonLocationRoot = Get-ChildItem $AgentShareLocation\wp\*\StandaloneSetup-*\ | Sort-Object { $_.CreationTime } -Descending | Select-Object -First 1 copy-item $JsonLocation.fullName -Destination $AgentShareLocation\OriginalSetupModules.json $json = Get-Content $JsonLocation.FullName -Raw | ConvertFrom-Json $json.components = $json.components | Where-Object { $_.name -ne 'financialreporting' } $json | ConvertTo-Json -Depth 100 | Out-File $JsonLocationRoot\Setupmodules.json -Force -Verbose $CLIXML += @{'Removed MR' = 'Success' } } else { Write-PSFMessage -Message "Error: Can't remove MR during anything other than PreDeployment" -Level VeryVerbose $CLIXML += @{'Removed MR' = 'Failed - Cant run outside of predeployment' } } } function Invoke-SQL { param( [string] $dataSource = ".\SQLEXPRESS", [string] $database = "MasterData", [string] $sqlCommand = $(throw "Please specify a query.") ) $connectionString = "Data Source=$dataSource; " + "Integrated Security=SSPI; " + "Initial Catalog=$database" $connection = new-object system.data.SqlClient.SQLConnection($connectionString) $command = new-object system.data.sqlclient.sqlcommand($sqlCommand, $connection) $connection.Open() $adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command $dataset = New-Object System.Data.DataSet $adapter.Fill($dataSet) | Out-Null $connection.Close() $dataSet.Tables } if ($MaintenanceModeOn) { if (!$AXDatabaseServer) { Write-PSFMessage -Level Error -Message "Config does not have AX Database Server cant turn on maintenance mode" } Write-PSFMessage -Message "Turning On Maintenance Mode" -Level Verbose $SQLQuery = "update SQLSYSTEMVARIABLES SET VALUE = 1 Where PARM = 'CONFIGURATIONMODE'" $Sqlresults = invoke-sql -datasource $AXDatabaseServer -database $AXDatabaseName -sqlcommand $SQLQuery if (!$PostDeployment -or !$PreDeployment) { foreach ($AXSFServer in $config.AXSFServerNames) { Restart-Computer -ComputerName $AXSFServer -Force } } Write-PSFMessage -Message "$SQLresults" -Level VeryVerbose if ($Sqlresults) { $CLIXML += @{'Turned On Maintenance Mode' = "Success - $SQLQuery" } Write-PSFMessage -Message "Turned On Maintenance Mode. Note AXSF needs to be restarted (or done as predeployment step) for maintenance mode to be fully on." -Level VeryVerbose } else { $CLIXML += @{'Turned Off Maintenance Mode' = "Success - $SQLQuery" } } } if ($MaintenanceModeOff) { if (!$AXDatabaseServer) { Write-PSFMessage -Level Error -Message "Config does not have AX Database Server cant turn off maintenance mode" } Write-PSFMessage -Message "Turning Off Maintenance Mode" -Level Verbose $SQLQuery = "update SQLSYSTEMVARIABLES SET VALUE = 0 Where PARM = 'CONFIGURATIONMODE'" $Sqlresults = invoke-sql -datasource $AXDatabaseServer -database $AXDatabaseName -sqlcommand $SQLQuery if ($PostDeployment -eq $false -or $PreDeployment -eq $false) { foreach ($AXSFServer in $config.AXSFServerNames) { Restart-Computer -ComputerName $AXSFServer -Force } } Write-PSFMessage -Message "$SQLresults" -Level VeryVerbose if ($Sqlresults) { $CLIXML += @{'Turned Off Maintenance Mode' = "Success - $SQLQuery" } Write-PSFMessage -Message "Turned Off Maintenance Mode. Note AXSF needs to be restarted (or done as predeployment step) for maintenance mode to be fully off." -Level VeryVerbose } else { $CLIXML += @{'Turned Off Maintenance Mode' = "Failed - $SQLQuery" } } } if ($EnableUserid) { ##Trim 8 characters if (!$AXDatabaseServer) { Write-PSFMessage -Level Error -Message "Config does not have AX Database Server cant enable user" } Write-PSFMessage -Message "Enabling $EnableUserid. Note: User must already exist in system" -Level Verbose $SQLQuery = "update userinfo SET Enable = 1, RECVERSION = RECVERSION +1 Where id = '$EnableUserid'" $SQLQuery2 = "select * from userinfo where enable = 1 and id = '$EnableUserid'" $SqlresultsUpdate = invoke-sql -datasource $AXDatabaseServer -database $AXDatabaseName -sqlcommand $SQLQuery $Sqlresults = invoke-sql -datasource $AXDatabaseServer -database $AXDatabaseName -sqlcommand $SQLQuery2 if ($Sqlresults) { if ($PreDeployment -or $PostDeployment) { $CLIXML += @{"Enable User $EnableUserid" = "Success - $SQLQuery" } } Write-PSFMessage -Message "$EnableUserid enabled." -Level VeryVerbose } else { if ($PreDeployment -or $PostDeployment) { $CLIXML += @{"Enable User $EnableUserid" = "Failed - $SQLQuery" } } Write-PSFMessage -Message "$EnableUserid enable failed." -Level VeryVerbose } Write-PSFMessage -Message "ID: $($SQLresults.ID) EnableFlag: $($SQLresults.Enable) " -Level VeryVerbose } if ($DisableUserid) { if (!$AXDatabaseServer) { Write-PSFMessage -Level Error -Message "Config does not have AX Database Server cant disable user" } else { Write-PSFMessage -Message "Disabling $DisableUserid. Note: User must already exist in system" -Level Verbose $SQLQuery = "update userinfo SET Enable = 0, RECVERSION = RECVERSION +1 Where id = '$DisableUserid'" $SQLQuery2 = "select * from userinfo where enable = 0 and id = '$DisableUserid'" $SQLQuery3 = "SELECT [USER_] ,[SECURITYROLE], t2.NAME, t2.AOTNAME FROM [dbo].[SECURITYUSERROLE] t1 inner join [SECURITYROLE] t2 on t1.SECURITYROLE=t2.RECID where USER_ = '$DisableUserid'" $SqlresultsUpdate = invoke-sql -datasource $AXDatabaseServer -database $AXDatabaseName -sqlcommand $SQLQuery $Sqlresults2 = invoke-sql -datasource $AXDatabaseServer -database $AXDatabaseName -sqlcommand $SQLQuery2 $Sqlresults3 = invoke-sql -datasource $AXDatabaseServer -database $AXDatabaseName -sqlcommand $SQLQuery3 Write-PSFMessage -Message "ID: $($SQLresults2.ID) EnableFlag: $($SQLresults2.Enable) " -Level VeryVerbose Write-PSFMessage -Message "User in the following groups" -Level VeryVerbose Write-PSFMessage -Message "$($($Sqlresults3.Name) -join ', ')" } if ($Sqlresults2) { if ($PreDeployment -or $PostDeployment) { $CLIXML += @{'Disable User' = "Success - $SQLQuery" } } write-PSFMessage -Message "$DisableUserid disabled." -Level VeryVerbose } else { if ($PreDeployment -or $PostDeployment) { $CLIXML += @{'Disable User' = "Failed - $SQLQuery" } } Write-PSFMessage -Message "$DisableUserid disable failed." -Level VeryVerbose } } if ($SQLQueryToRun) { if (!$AXDatabaseServer) { Write-PSFMessage -Level Error -Message "Config does not have AX Database Server cant run SQL command" } $Sqlresults = invoke-sql -datasource $AXDatabaseServer -database $AXDatabaseName -sqlcommand $SQLQueryToRun Write-PSFMessage -Message "$SQLresults" -Level VeryVerbose $CountofSQLScripts = $($CLIXML.GetEnumerator() | Where-Object { $_.Name -like "SQL*" }).Count $CountOfSQLScripts = $CountofSQLScripts + 1 if ($Sqlresults) { $CLIXML += @{"SQL$CountOfSQLScripts" = "Success - $SQLQueryToRun" } } else { $CLIXML += @{"SQL$CountOfSQLScripts" = "Failed - $SQLQueryToRun" } } } ##EXPORT FILE AFTER CHANGES $CLIXML | Export-Clixml $newfile.FullName if ($MSTeamsURI) { Write-PSFMessage -Level VeryVerbose -Message "MSTeamsURI defined sending message" $MSTeamsFormmatedJSONofCLIItems = "" foreach ($XMLItem in $CLIXML.GetEnumerator()) { $WorkingJSON = @" ,{ "name": "$($XMLItem.Name)", "value": "$($XMLItem.Value)" } "@ $MSTeamsFormmatedJSONofCLIItems += $WorkingJSON } if ($PreDeployment) { $status = 'PreDeployment Started' } if ($PostDeployment) { $status = 'Deployment Finished. PostDeployment Started' } if ($MSTeamsCustomStatus) { $status = "$MSTeamsCustomStatus" } if (!$MSTeamsBuildName) { $MSTeamsBuildName = $config.LastFullyPreppedCustomModuleAsset } if ($MSTeamsFormmatedJSONofCLIItems) { $bodyjson = @" { "@type": "MessageCard", "@context": "http://schema.org/extensions", "themeColor": "ff0000", "title": "D365 $LCSEnvironmentName $status", "summary": "D365 $LCSEnvironmentName $status", "sections": [{ "facts": [{ "name": "Environment", "value": "[$LCSEnvironmentName]($clienturl)" },{ "name": "Build Version/Name", "value": "$MSTeamsBuildName" },{ "name": "Status", "value": "$status" }$MSTeamsFormmatedJSONofCLIItems], "markdown": true }] } "@ } else { $bodyjson = @" { "@type": "MessageCard", "@context": "http://schema.org/extensions", "themeColor": "ff0000", "title": "D365 $LCSEnvironmentName $status", "summary": "D365 $LCSEnvironmentName $status", "sections": [{ "facts": [{ "name": "Environment", "value": "[$LCSEnvironmentName]($clienturl)" },{ "name": "Build Version/Name", "value": "$MSTeamsBuildName" },{ "name": "Status", "value": "$status" }], "markdown": true }] } "@ } if ($MSTeamsExtraDetails) { if ($MSTeamsFormmatedJSONofCLIItems) { $bodyjson = @" { "@type": "MessageCard", "@context": "http://schema.org/extensions", "themeColor": "ff0000", "title": "D365 $LCSEnvironmentName $status", "summary": "D365 $LCSEnvironmentName $status", "sections": [{ "facts": [{ "name": "Environment", "value": "[$LCSEnvironmentName]($clienturl)" },{ "name": "Build Version", "value": "$MSTeamsBuildName" },{ "name": "Details", "value": "[$MSTeamsExtraDetails]($MSTeamsExtraDetailsURI)" },{ "name": "Status", "value": "$status" }$MSTeamsFormmatedJSONofCLIItems], "markdown": true }] } "@ } else { $bodyjson = @" { "@type": "MessageCard", "@context": "http://schema.org/extensions", "themeColor": "ff0000", "title": "D365 $LCSEnvironmentName $status", "summary": "D365 $LCSEnvironmentName $status", "sections": [{ "facts": [{ "name": "Environment", "value": "[$LCSEnvironmentName]($clienturl)" },{ "name": "Build Version", "value": "$MSTeamsBuildName" },{ "name": "Details", "value": "[$MSTeamsExtraDetails]($MSTeamsExtraDetailsURI)" },{ "name": "Status", "value": "$status" }], "markdown": true }] } "@ } } Write-PSFMessage -Message "Calling $MSTeamsURI with Post of $bodyjson" -Level VeryVerbose $WebRequestResults = Invoke-WebRequest -uri $MSTeamsURI -ContentType 'application/json' -Body $bodyjson -UseBasicParsing -Method Post -Verbose Write-PSFMessage -Message "$WebRequestResults" -Level VeryVerbose } } END { } } |