microsoft / navcontainerhelper

Official Microsoft repository for BcContainerHelper, a PowerShell module, which makes it easier to work with Business Central Containers on Docker.
MIT License
382 stars 243 forks source link

Another PS7 Error? Could not load type 'System.Management.Automation.PSSnapIn' from assembly #3568

Open epernst opened 4 months ago

epernst commented 4 months ago

Here we go again.

With reference to issue https://github.com/microsoft/navcontainerhelper/issues/3527, the same script is now failing when using BC v24.1 and BCCH 6.0.18. Building the container works fine, it fails when I'm using Invoce-ScriptInBcContainer, where I'm trying to Import-Module SQLPS. Could not load type 'System.Management.Automation.PSSnapIn' from assembly 'System.Management.Automation, Version=7.4.2.500, Culture=neutral, PublicKeyToken=31bf3856ad364e35' Same scripts works fine for v23 and earlier. I can also see the same error reported in issue https://github.com/microsoft/navcontainerhelper/issues/3541.

Based on the version (7.4.2.500) I assume it has something to do with the PowerShell version?

So, let me start by asking once again. When should we be using PowerShell 5 vs 7? When should we be specifying PWSH when invoking scripts in the container, and when not?

freddydk commented 4 months ago

Let me start by answering once again then:-) BC24 and above runs PS7 inside the container by default. All versions before BC24 runs PS5.1.

As you probably know by now, all cmdlets in BC24 and above are PS7 with a bridge between PS5.1 and PS7. Yes - you can run everything in PS5.1 inside the container (still), but performance will be much slower than running PS7. Therefore, I have changed most scripts in BcContainerHelper to be able to run in PS7 - for the places, where the script was unable to run PS7 - I have used -usePsSession:$false -usePwsh:$false when invoking the script.

If you have your own scripts, you will need to do the same (or run PS5.1 always by setting $bcContainerHelperConfig.usePwshForBc24 = $false) - this will make everything run PS5.1 and you can continue as before with degraded performance however.

I cannot do magic - SQLPS doesn't exist in PS7 - only the SqlServer module, and that isn't compatible. I have installed the SqlServer module in PS7 by default and added some aliases to get some common scripts to run.

So,... - you are on your own here - if you run PS5.1 - your scripts probably works. If you want to run PS7 for performance - you need to modify your scripts to make them run.

Sorry - but this is the best I can do.

freddydk commented 4 months ago

I am always open for good ideas, which can make life easier for everybody - feel free to suggest stuff - but not to make me load SQLPS on PS7 - that cannot be done.

ernestasjuska commented 4 months ago

I am always open for good ideas, which can make life easier for everybody - feel free to suggest stuff - but not to make me load SQLPS on PS7 - that cannot be done.

It can be done. But you must use PowerShell remoting to accomplish that (Import-Module -UseWindowsPowerShell):

This is bad:

PS C:\Users\ernjus> Invoke-ScriptInBcContainer -containerName $ContainerName -scriptblock { Import-Module -Name SQLPS; Invoke-Sqlcmd -ServerInstance 'docker.softera.lt' -Query 'SELECT 1' -Username 'containeruser' -Password 'Password1.' }
Could not load type 'System.Management.Automation.PSSnapIn' from assembly 'System.Management.Automation, Version=7.4.2.500, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.

Container Free Physical Memory: 13.3Gb
Disk C: Free 124Gb from 127Gb

Services in container bc123:
Exception: C:\Users\ernjus\OneDrive - Softera Baltic UAB\Documents\PowerShell\Modules\BcContainerHelper\6.0.18\ContainerHandling\Invoke-ScriptInNavContainer.ps1:301
Line |
 301 |                          throw $errorMessage
     |                          ~~~~~~~~~~~~~~~~~~~
     | Could not load type 'System.Management.Automation.PSSnapIn' from assembly 'System.Management.Automation, Version=7.4.2.500, Culture=neutral,
     | PublicKeyToken=31bf3856ad364e35'.

This is ok:

PS C:\Users\ernjus> Invoke-ScriptInBcContainer -containerName $ContainerName -scriptblock { Import-Module -Name SQLPS -UseWindowsPowerShell; Invoke-Sqlcmd -
ServerInstance 'docker.softera.lt' -Query 'SELECT 1' -Username 'containeruser' -Password 'Password1.' }

RunspaceId                           Column1
----------                           -------
0b40cdc5-eb64-474c-b386-a40b131e43f6       1

The main downside is performance hit because PowerShell needs a few seconds to create PowerShell 5 session and load the module there.

Also, once you load the module, you don't need to call Import-Module for the next Invoke-ScriptInBcContainer, but it still feels slow rather slow.

The slowness seems to be caused the way Invoke-ScriptInBcContainer works - if I import module and run query inside the container everything works nearly instantly. Maybe new parameter should be added to Invoke-ScriptInBcContainer to skip loading of BC modules or only load them once per PS session.

freddydk commented 4 months ago

There is nothing forcing you to use Invoke-ScriptInBcContainer. The benefit of that is that it works using docker exec or sessions and auto-loads modules. If you know what you are doing - create a PSSession and use Invoke-Command instead.

I decided against the -useWindowsPowershell mostly because it sounds like a giant hack - but maybe it isn't. Kind of like the bridge - any swapping back and forth between PS5 and PS7 must be slow - so I decided to face the issues - enable PS7 for BC24 and fix everything I encountered.

Problem for me was that it took most of 4-6 weeks.