diff --git a/BC.HelperFunctions.ps1 b/BC.HelperFunctions.ps1 index 893a5bf79..5e7504d42 100644 --- a/BC.HelperFunctions.ps1 +++ b/BC.HelperFunctions.ps1 @@ -15,7 +15,9 @@ function Get-ContainerHelperConfig { "genericImageNameFilesOnly" = 'mcr.microsoft.com/businesscentral:{1}-filesonly' "usePsSession" = $true "usePwshForBc24" = $true - "tryWinRmSession" = !$isAdministrator + "useSslForWinRmSession" = $true + "tryWinRmSession" = $isPsCore -or !$isAdministrator + "alwaysUseWinRmSession" = $false "addTryCatchToScriptBlock" = $true "killPsSessionProcess" = $false "useVolumes" = $false diff --git a/ContainerHandling/Enter-NavContainer.ps1 b/ContainerHandling/Enter-NavContainer.ps1 index ba0607817..b024fbd28 100644 --- a/ContainerHandling/Enter-NavContainer.ps1 +++ b/ContainerHandling/Enter-NavContainer.ps1 @@ -19,7 +19,7 @@ function Enter-BcContainer { Process { if ($bcContainerHelperConfig.usePsSession) { - $session = Get-BcContainerSession -containerName $containerName -silent -tryWinRmSession + $session = Get-BcContainerSession -containerName $containerName -silent Enter-PSSession -Session $session if ($session.ComputerType -eq 'Container') { Invoke-Command -Session $session -ScriptBlock { diff --git a/ContainerHandling/Get-NavContainerSession.ps1 b/ContainerHandling/Get-NavContainerSession.ps1 index f4a2bc5fe..5daffa3ef 100644 --- a/ContainerHandling/Get-NavContainerSession.ps1 +++ b/ContainerHandling/Get-NavContainerSession.ps1 @@ -17,6 +17,8 @@ function Get-BcContainerSession { Param ( [string] $containerName = $bcContainerHelperConfig.defaultContainerName, [switch] $tryWinRmSession = $bccontainerHelperConfig.tryWinRmSession, + [switch] $alwaysUseWinRmSession = $bccontainerHelperConfig.alwaysUseWinRmSession, + [switch] $usePwsh = $bccontainerHelperConfig.usePwshForBc24, [switch] $silent, [switch] $reinit ) @@ -37,34 +39,40 @@ function Get-BcContainerSession { } } if (!$session) { + [System.Version]$platformVersion = Get-BcContainerPlatformVersion -containerOrImageName $containerName + if ($platformVersion -lt [System.Version]"24.0.0.0") { + $usePwsh = $false + } + $configurationName = 'Microsoft.PowerShell' + if ($usePwsh) { + $configurationName = 'PowerShell.7' + } if ($isInsideContainer) { $session = New-PSSession -Credential $bcContainerHelperConfig.WinRmCredentials -ComputerName $containerName -Authentication Basic -UseSSL -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck) } - elseif ($isAdministrator) { + elseif ($isAdministrator -and !$bcContainerHelperConfig.alwaysUseWinRmSession) { try { $containerId = Get-BcContainerId -containerName $containerName - $session = New-PSSession -ContainerId $containerId -RunAsAdministrator -ErrorAction SilentlyContinue + $session = New-PSSession -ContainerId $containerId -RunAsAdministrator -ErrorAction SilentlyContinue -ConfigurationName $configurationName } catch {} } if (!$session) { - if (!$tryWinRmSession) { - throw "Unable to create a session for container $containerName (tryWinRmSession is false)" + if (!($alwaysUseWinRmSession -or $tryWinRmSession)) { + throw "Unable to create session for container $containerName (alwaysUseWinRmSession and tryWinRmSession are both false)" + } + $useSSL = $bcContainerHelperConfig.useSslForWinRmSession $UUID = (Get-CimInstance win32_ComputerSystemProduct).UUID $credential = New-Object PSCredential -ArgumentList 'winrm', (ConvertTo-SecureString -string $UUID -AsPlainText -force) - Invoke-ScriptInBcContainer -containerName $containerName -useSession:$false -scriptblock { Param([PSCredential] $credential) - $winrmuser = get-localuser -name $credential.UserName -ErrorAction SilentlyContinue - if (!$winrmuser) { - $cert = New-SelfSignedCertificate -DnsName "dontcare" -CertStoreLocation Cert:\LocalMachine\My - winrm create winrm/config/Listener?Address=*+Transport=HTTPS ('@{Hostname="dontcare"; CertificateThumbprint="' + $cert.Thumbprint + '"}') | Out-Null - winrm set winrm/config/service/Auth '@{Basic="true"}' | Out-Null - Write-Host "`nCreating Container user $($credential.UserName)" - New-LocalUser -AccountNeverExpires -PasswordNeverExpires -FullName $credential.UserName -Name $credential.UserName -Password $credential.Password | Out-Null - Add-LocalGroupMember -Group administrators -Member $credential.UserName | Out-Null - } - } -argumentList $credential - $session = New-PSSession -Credential $credential -ComputerName $containerName -Authentication Basic -useSSL -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck) + if ($useSSL) { + $sessionOption = New-PSSessionOption -Culture 'en-US' -UICulture 'en-US' -SkipCACheck -SkipCNCheck + $Session = New-PSSession -ConnectionUri "https://$($containerName):5986" -Credential $credential -Authentication Basic -SessionOption $sessionOption -ConfigurationName $configurationName + } + else { + $sessionOption = New-PSSessionOption -Culture 'en-US' -UICulture 'en-US' + $Session = New-PSSession -ConnectionUri "http://$($containerName):5985" -Credential $credential -Authentication Basic -SessionOption $sessionOption -ConfigurationName $configurationName + } } $newsession = $true } diff --git a/ContainerHandling/Invoke-ScriptInNavContainer.ps1 b/ContainerHandling/Invoke-ScriptInNavContainer.ps1 index bee7bff7a..c63a11241 100644 --- a/ContainerHandling/Invoke-ScriptInNavContainer.ps1 +++ b/ContainerHandling/Invoke-ScriptInNavContainer.ps1 @@ -31,39 +31,20 @@ function Invoke-ScriptInBcContainer { ) $file = Join-Path $bcContainerHelperConfig.hostHelperFolder ([GUID]::NewGuid().Tostring()+'.ps1') - $containerFile = "" - $shell = 'powershell' - if ($usePwsh) { - [System.Version]$platformVersion = Get-BcContainerPlatformVersion -containerOrImageName $containerName - if ($platformVersion -ge [System.Version]"24.0.0.0") { - $useSession = $false - $shell = 'pwsh' - } - else { - $usePwsh = $false - } - } - if (-not $usePwsh) { - if ($isInsideContainer) { - $useSession = $true - } - else { - $containerFile = Get-BcContainerPath -containerName $containerName -path $file - if ("$containerFile" -eq "") { - $useSession = $true - } - } + $containerFile = $containerFile = Get-BcContainerPath -containerName $containerName -path $file + if ($isInsideContainer -or "$containerFile" -eq "") { + $useSession = $true } if ($useSession) { try { - $session = Get-BcContainerSession -containerName $containerName -silent + $session = Get-BcContainerSession -containerName $containerName -silent -usePwsh:$usePwsh } catch { if ($isInsideContainer) { Write-Host "Error trying to establish session, retrying in 5 seconds" Start-Sleep -Seconds 5 - $session = Get-BcContainerSession -containerName $containerName -silent + $session = Get-BcContainerSession -containerName $containerName -silent -usePwsh:$usePwsh } else { $useSession = $false @@ -129,7 +110,14 @@ function Invoke-ScriptInBcContainer { } } else { if ("$containerFile" -eq "") { - $containerFile = Get-BcContainerPath -containerName $containerName -path $file -throw + throw "$($bcContainerHelperConfig.hostHelperFolder) is not shared with the container, cannot invoke scripts in container without using a session" + } + $shell = 'powershell' + if ($usePwsh) { + [System.Version]$platformVersion = Get-BcContainerPlatformVersion -containerOrImageName $containerName + if ($platformVersion -ge [System.Version]"24.0.0.0") { + $shell = 'pwsh' + } } $hostOutputFile = "$file.output" $containerOutputFile = "$containerFile.output" diff --git a/ContainerHandling/New-NavContainer.ps1 b/ContainerHandling/New-NavContainer.ps1 index b26336afc..4f833613a 100644 --- a/ContainerHandling/New-NavContainer.ps1 +++ b/ContainerHandling/New-NavContainer.ps1 @@ -1597,8 +1597,75 @@ if (!$restartingInstance) { Add-LocalGroupMember -Group administrators -Member '+$bcContainerHelperConfig.WinRmCredentials.UserName+' } ') | Add-Content -Path "$myfolder\AdditionalSetup.ps1" + } + else { + $UUID = (Get-CimInstance win32_ComputerSystemProduct).UUID + (' +if (!$restartingInstance) { + Write-Host "Enable PSRemoting and setup user for winrm" + Enable-PSRemoting | Out-Null + Get-PSSessionConfiguration | Out-null + pwsh.exe -Command "Enable-PSRemoting -WarningAction SilentlyContinue | Out-Null; Get-PSSessionConfiguration | Out-Null" + $credential = New-Object PSCredential -ArgumentList "winrm", (ConvertTo-SecureString -string "'+$UUID+'" -AsPlainText -force) + New-LocalUser -AccountNeverExpires -PasswordNeverExpires -FullName $credential.UserName -Name $credential.UserName -Password $credential.Password | Out-Null + Add-LocalGroupMember -Group administrators -Member $credential.UserName | Out-Null + winrm set winrm/config/service/Auth ''@{Basic="true"}'' | Out-Null +} +') | Add-Content -Path "$myfolder\AdditionalSetup.ps1" + if ($bccontainerHelperConfig.useSslForWinRmSession) { + $additionalParameters += @("--expose 5986") + (' +if (!$restartingInstance) { + Write-Host "Creating self-signed certificate for winrm" + $cert = New-SelfSignedCertificate -CertStoreLocation cert:\localmachine\my -DnsName $env:computername -NotBefore (get-date).AddDays(-1) -NotAfter (get-date).AddYears(5) -Provider "Microsoft RSA SChannel Cryptographic Provider" -KeyLength 2048 + winrm create winrm/config/Listener?Address=*+Transport=HTTPS ("@{Hostname=""$env:computername""; CertificateThumbprint=""$($cert.Thumbprint)""}") | Out-Null +} +') | Add-Content -Path "$myfolder\AdditionalSetup.ps1" + } + else { + $additionalParameters += @("--expose 5985") + (' +if (!$restartingInstance) { + Write-Host "Allow unencrypted communication to container" + winrm set winrm/config/service ''@{AllowUnencrypted="true"}'' | Out-Null +} +') | Add-Content -Path "$myfolder\AdditionalSetup.ps1" + } + if (-not $bccontainerHelperConfig.useSslForWinRmSession) { + try { + [xml]$conf = winrm get winrm/config/client -format:pretty + $trustedHosts = @($conf.Client.TrustedHosts.Split(',')) + if (-not $trustedHosts) { + $trustedHosts = @() + } + $isTrusted = $trustedHosts | Where-Object { $containerName -like $_ } + if (!($isTrusted)) { + if (!$isAdministrator) { + Write-Host "$containerName is not a trusted host. You need to get an administrator to add $containerName to the trusted winrm hosts on your machine" + } + else { + Write-Host "Adding $containerName to trusted hosts ($($trustedHosts -join ','))" + $trustedHosts += $containerName + winrm set winrm/config/client "@{TrustedHosts=""$($trustedHosts -join ',')""}" | Out-Null + } + } + if ($conf.Client.AllowUnencrypted -eq 'false') { + if (!$isAdministrator) { + Write-Host "Unencrypted communication is not allowed. You need to get an administrator to allow unencrypted communication" + } + else { + Write-Host "Allow unencrypted communication" + winrm set winrm/config/client '@{AllowUnencrypted="true"}' | Out-Null + } + } + } + catch { + Write-Host "Unexpected error when checking winrm configuration, you might not be able to connect to the container using winrm unencrypted" + } + } } + if ($includeCSide) { $programFilesFolder = Join-Path $containerFolder "Program Files" New-Item -Path $programFilesFolder -ItemType Directory -ErrorAction Ignore | Out-Null diff --git a/ContainerHandling/Remove-NavContainer.ps1 b/ContainerHandling/Remove-NavContainer.ps1 index f3a918325..a12f06c29 100644 --- a/ContainerHandling/Remove-NavContainer.ps1 +++ b/ContainerHandling/Remove-NavContainer.ps1 @@ -62,6 +62,18 @@ try { . (Join-Path $PSScriptRoot "updatehosts.ps1") -hostsFile "c:\windows\system32\drivers\etc\hosts" -theHostname $tenantHostname -theIpAddress "" } + if ($isAdministrator) { + try { + [xml]$conf = winrm get winrm/config/client -format:pretty + $trustedHosts = $conf.Client.TrustedHosts.Split(',') + if ($trustedHosts -contains $containerName) { + Write-Host "Removing $containerName from trusted hosts ($($trustedHosts -join ','))" + winrm set winrm/config/client "@{TrustedHosts=""$(@($trustedHosts | Where-Object { $_ -ne $containerName }) -join ',')""}" | Out-Null + } + } + catch {} + } + if ($myVolume) { Write-Host "Removing volume $myVolumeName" docker volume remove $myVolumeName