I am developing a server side Blazor app to facilitate Exchange online management via a GUI. I have a helper class that setups the runspace and communicates the results back to the the Blazor component. I added the class via an scoped Dependency Injection.
The helper class is setup as:
InitialSessionState runspaceConfiguration = InitialSessionState.CreateDefault();
runspaceConfiguration.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.RemoteSigned;
runspaceConfiguration.ImportPSModule("ExchangeOnlineManagement");
runspaceConfiguration.ThrowOnRunspaceOpenError = true;
_runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
// Open local runspace
_runspace.Open();
_shell = PowerShell.Create();
_shell.Runspace = _runspace;
SetUpEventHandlers();
My function to execute commands is a follow:
public async Task ExecuteScript(string scriptContents)
{
_shell.AddScript(scriptContents);
OutputEventArgs rtc = new() {
Data = await _shell.InvokeAsync().ConfigureAwait(true)
};
_shell.Streams.ClearStreams();
_shell.Commands.Clear();
ResultsAvailable?.Invoke(this, rtc);
}
To connect to Exchnage Online I use a certificate, it looks like:
string? certificateThumbPrint = config.GetValue<string>("certificateThumbPrint");
string? appId = config.GetValue<string>("appId");
string? tenant = config.GetValue<string>("tenant");
logger.Info($"Running : Connect-ExchangeOnline -Certificate {certificateThumbPrint} -AppID {appId} -Organization {tenant} -ShowProgress $false -ShowBanner $false");
string scriptContents = $"Connect-ExchangeOnline -CertificateThumbPrint {certificateThumbPrint} -AppID {appId} -Organization {tenant}";
await objPowerShell.ExecuteScript(scriptContents);
I have setup EventHandler's that handle all the streams and results async, and everything works fine for one user. The problem is when I have multiple users. It still all works fine, except when one user disconnects the session, all active connections to the Exchange Online environment are disconnected. As I am using EXO v3, I cannot save the PSSession and import it.
So my question is how can I disconnect one user without having an impact on the other.
I did tried to do the same thing directly in PowerShell:
$Initialstate = [InitialSessionState]::CreateDefault()
$RunspacePool = [runspacefactory]::CreateRunspacePool(1,5)
$RunspacePool.Open()
$Runspace1 = [runspacefactory]::CreateRunspace()
$PowerShell1 = [powershell]::Create()
$PowerShell1.RunspacePool = $RunspacePool
$Runspace1.Open()
[void]$PowerShell1.AddScript({
$cert = Get-ChildItem Cert:\LocalMachine\My\0CF..4C17.
Connect-ExchangeOnline -Certificate $cert -AppID 70539...5889 -Organization myorg.onmicrosoft.com
})
$PowerShell1.Invoke()
$PowerShell1.Commands.Clear()
[void]$PowerShell1.AddScript({
Get-ConnectionInformation
})
$conn1 = $PowerShell1.Invoke()
$PowerShell1.Commands.Clear()
[void]$PowerShell1.AddScript({
Get-MailBox "ue*" -resultsize 2 | Select-Object PrimarySmtpAddress
})
$mbx1 = $PowerShell1.Invoke()
$mbx1 # Gets the info ok
$PowerShell2 = [powershell]::Create()
$PowerShell2.RunspacePool = $RunspacePool
[void]$PowerShell2.AddScript({
$cert = Get-ChildItem Cert:\LocalMachine\My\0CF.4C17D
Connect-ExchangeOnline -Certificate $cert -AppID 70539...5889 -Organization myorg.onmicrosoft.com
})
$PowerShell2.Invoke()
$PowerShell2.Commands.Clear()
[void]$PowerShell2.AddScript({
Get-ConnectionInformation
})
$conn2 = $PowerShell2.Invoke()
$PowerShell2.Commands.Clear()
[void]$PowerShell2.AddScript({
Get-MailBox "uz*" -resultsize 2 | Select-Object PrimarySmtpAddress
})
$mbx2 = $PowerShell2.Invoke()
$mbx2 # Gets the info ok
But when I execute now "Get-ConnectionInformation" I see 2 connections and "Disconnect-ExchangeOnline" disconnects them both. So, how can I only disconnect one ?