diff --git a/d365fo.tools/d365fo.tools.psd1 b/d365fo.tools/d365fo.tools.psd1
index 8f7981cd..b138df48 100644
--- a/d365fo.tools/d365fo.tools.psd1
+++ b/d365fo.tools/d365fo.tools.psd1
@@ -168,6 +168,7 @@
'Get-D365TfsUri',
'Get-D365TfsWorkspace',
+ 'Get-D365UdeDatabaseCredential',
'Get-D365Url',
'Get-D365User',
'Get-D365UserAuthenticationDetail',
@@ -310,6 +311,8 @@
'Set-D365SqlPackagePath',
'Set-D365SysAdmin',
+ 'Set-D365UdeDatabaseCredential',
+
'Set-D365WebConfigDatabase',
'Set-D365WebServerType',
@@ -323,6 +326,8 @@
'Start-D365EnvironmentV2',
'Start-D365EventTrace',
+ 'Start-D365UdeSsmsSession',
+
'Stop-D365Environment',
'Stop-D365EventTrace',
diff --git a/d365fo.tools/functions/get-d365udedatabasecredential.ps1 b/d365fo.tools/functions/get-d365udedatabasecredential.ps1
new file mode 100644
index 00000000..84dd85f2
--- /dev/null
+++ b/d365fo.tools/functions/get-d365udedatabasecredential.ps1
@@ -0,0 +1,43 @@
+function Get-D365UdeDatabaseCredential {
+ [CmdletBinding()]
+ param (
+ [Alias("Name")]
+ [string] $Id = "*",
+
+ [switch] $ShowPassword
+ )
+
+ begin {
+ if ($null -eq (Get-Module TUN.CredentialManager -ListAvailable)) {
+ Write-PSFMessage -Level Host -Message "This cmdlet needs the TUN.CredentialManager module. Please install it from the PowerShell Gallery with Install-Module -Name TUN.CredentialManager and try again."
+ Stop-PSFFunction -Message "Stopping because the TUN.CredentialManager module is not available."
+
+ return
+ }
+
+ if (Test-PSFFunctionInterrupt) { return }
+
+ Import-Module TUN.CredentialManager
+ }
+
+ process {
+ if (Test-PSFFunctionInterrupt) { return }
+
+ $credentials = [hashtable](Get-PSFConfigValue -FullName "d365fo.tools.ude.credentials")
+
+ $col = @(
+ foreach ($key in $credentials.Keys) {
+ if ($key -like $Id) {
+ $credentials[$key]
+ }
+ }
+ )
+
+ if ($ShowPassword) {
+ $col
+ }
+ else {
+ $col | Select-PSFObject -Property * -ExcludeProperty Password
+ }
+ }
+}
\ No newline at end of file
diff --git a/d365fo.tools/functions/set-d365udedatabasecredential.ps1 b/d365fo.tools/functions/set-d365udedatabasecredential.ps1
new file mode 100644
index 00000000..049262db
--- /dev/null
+++ b/d365fo.tools/functions/set-d365udedatabasecredential.ps1
@@ -0,0 +1,75 @@
+
+function Set-D365UdeDatabaseCredential {
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")]
+ [CmdletBinding()]
+ param (
+ [Parameter(Mandatory = $true)]
+ [string] $Id,
+
+ [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
+ [Alias("DatabaseServer")]
+ [Alias("ServerName")]
+ [string] $Server,
+
+ [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
+ [Alias("DatabaseName")]
+ [string] $Database,
+
+ [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
+ [Alias("SqlUser")]
+ [string] $Username,
+
+ [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
+ [Alias("SqlPwd")]
+ [string] $Password,
+
+ [Alias("SQLJITExpirationTime")]
+ [datetime] $ValidUntil = (Get-Date).AddHours(8)
+ )
+
+ begin {
+ if ($null -eq (Get-Module TUN.CredentialManager -ListAvailable)) {
+ Write-PSFMessage -Level Host -Message "This cmdlet needs the TUN.CredentialManager module. Please install it from the PowerShell Gallery with Install-Module -Name TUN.CredentialManager and try again."
+ Stop-PSFFunction -Message "Stopping because the TUN.CredentialManager module is not available."
+
+ return
+ }
+
+ if (Test-PSFFunctionInterrupt) { return }
+
+ Import-Module TUN.CredentialManager
+ }
+
+ process {
+ if (Test-PSFFunctionInterrupt) { return }
+
+ $SqlServerGUID = "8c91a03d-f9b4-46c0-a305-b5dcc79ff907"
+
+ $details = [PSCustomObject][ordered]@{
+ Id = $Id
+ Server = $($Server)
+ Database = $($Database)
+ Username = $($Username)
+ Password = $($Password)
+ Expiration = $($ValidUntil.ToString("s"))
+ }
+
+ # Setting up the SQL Server Management Studio (SSMS) Credential for version 20 - 21
+ 20, 21 | ForEach-Object {
+ New-StoredCredential `
+ -UserName $Username `
+ -Password $Password `
+ -Persist LocalMachine `
+ -Target "Microsoft:SSMS:$($_):$($Server):$($Username):$($SqlServerGUID):1" > $null
+ }
+
+ $credentials = [hashtable](Get-PSFConfigValue -FullName "d365fo.tools.ude.credentials")
+ $credentials."$Id" = $details
+
+ Set-PSFConfig -FullName "d365fo.tools.ude.credentials" -Value $credentials
+ Register-PSFConfig -FullName "d365fo.tools.ude.credentials" -Scope UserDefault
+
+ Get-D365UdeDatabaseCredential -Id $Id
+ }
+}
\ No newline at end of file
diff --git a/d365fo.tools/functions/start-d365udessmssession.ps1 b/d365fo.tools/functions/start-d365udessmssession.ps1
new file mode 100644
index 00000000..480b0b65
--- /dev/null
+++ b/d365fo.tools/functions/start-d365udessmssession.ps1
@@ -0,0 +1,41 @@
+
+function Start-D365UdeSsmsSession {
+ param (
+ [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
+ [string] $Id,
+
+ [ValidateSet(20, 21)]
+ [int] $Version = 20
+ )
+
+ process {
+ $udeCreds = Get-D365UdeDatabaseCredential -Id $Id
+
+ if ($null -eq $udeCreds) {
+ Write-PSFMessage -Level Host -Message "No credential found for Id '$Id'. Please check the Id and try again."
+ Stop-PSFFunction -Message "Stopping because no matching credential was found."
+
+ return
+ }
+
+ # Hack to get the SSMS executable path from the registry
+ $ssmsInstalled = Get-ChildItem `
+ -Path Registry::HKEY_CLASSES_ROOT\ssms.*\shell\Open\Command | `
+ Select-Object -ExpandProperty PsPath | `
+ ForEach-Object { (Get-ItemProperty -Path $_)."(Default)" } | `
+ Select-String -Pattern '^[\"]?(.*ssms\.exe)["]?\s*"%1"' | `
+ ForEach-Object { $_.Matches.Groups[1].Value } | Select-Object -Unique
+
+ $executablePath = $ssmsInstalled | `
+ Where-Object { $_ -match "Microsoft SQL Server Management Studio $($Version)\b" } | `
+ Select-Object -First 1
+
+ if ([string]::IsNullOrWhiteSpace($executablePath)) {
+ Write-PSFMessage -Level Host -Message "Could not find a valid SSMS executable for version $Version. Please ensure the version is installed or try a different version."
+ Stop-PSFFunction -Message "Stopping because SSMS executable was not found."
+ return
+ }
+
+ & $executablePath -S $($udeCreds.Server) -d $($udeCreds.Database) -U $($udeCreds.Username)
+ }
+}
\ No newline at end of file
diff --git a/d365fo.tools/internal/configurations/configuration.ps1 b/d365fo.tools/internal/configurations/configuration.ps1
index 40fc2dd8..c0522b64 100644
--- a/d365fo.tools/internal/configurations/configuration.ps1
+++ b/d365fo.tools/internal/configurations/configuration.ps1
@@ -40,3 +40,5 @@ Set-PSFConfig -FullName "d365fo.tools.path.rsatplayback" -Value "C:\Users\$($env
Set-PSFConfig -FullName "d365fo.tools.path.azcopy" -Value "C:\temp\d365fo.tools\AzCopy\AzCopy.exe" -Initialize -Description "Path to the default location where AzCopy.exe is located."
Set-PSFConfig -FullName "d365fo.tools.path.nuget" -Value "C:\temp\d365fo.tools\nuget\nuget.exe" -Initialize -Description "Path to the default location where nuget.exe is located."
+
+Set-PSFConfig -FullName "d365fo.tools.ude.credentials" -Value @{} -Initialize -Description "Object that stores different Ude Database credentials and their details."
diff --git a/d365fo.tools/internal/tepp/assignment.ps1 b/d365fo.tools/internal/tepp/assignment.ps1
index 6b7f4237..29acdd4c 100644
--- a/d365fo.tools/internal/tepp/assignment.ps1
+++ b/d365fo.tools/internal/tepp/assignment.ps1
@@ -34,3 +34,8 @@ Register-PSFTeppArgumentCompleter -Command Add-D365BroadcastMessageConfig -Param
#Event Trace
Register-PSFTeppArgumentCompleter -Command Start-D365EventTrace -Parameter ProviderName -Name d365fo.tools.event.trace.providers
Register-PSFTeppArgumentCompleter -Command Start-D365EventTrace -Parameter OutputFormat -Name d365fo.tools.event.trace.format.options
+
+#UDE Credentials
+Register-PSFTeppArgumentCompleter -Command Get-D365UdeDatabaseCredential -Parameter Id -Name "d365fo.tools.ude.credentials"
+Register-PSFTeppArgumentCompleter -Command Start-D365UdeSsmsSession -Parameter Id -Name "d365fo.tools.ude.credentials"
+Register-PSFTeppArgumentCompleter -Command Set-D365UdeDatabaseCredential -Parameter Id -Name "d365fo.tools.ude.credentials"
diff --git a/d365fo.tools/internal/tepp/configurations.tepp.ps1 b/d365fo.tools/internal/tepp/configurations.tepp.ps1
new file mode 100644
index 00000000..e1d383c5
--- /dev/null
+++ b/d365fo.tools/internal/tepp/configurations.tepp.ps1
@@ -0,0 +1,3 @@
+$scriptBlock = { Get-D365UdeDatabaseCredential | Sort-Object Id | Select-Object -ExpandProperty Id }
+
+Register-PSFTeppScriptblock -Name "d365fo.tools.ude.credentials" -ScriptBlock $scriptBlock -Mode Simple