powershellexchange-serverexchange-server-2010

Handling PSSessions in PS script


So my issue is that this script will run fine the first time but if I try running it again, the PSSessions are still active despite the

Get-PSSession | Remove-PSSession

lines. I've tried other methods like calling the computernames or instanceIDs but still won't close them. I'm not sure why the sessions aren't closing but it's the last thing that is keeping this script from working correctly.

Also this is made from the Microsoft article here: https://support.microsoft.com/en-us/help/2956029/migrationpermanentexception-cannot-find-a-recipient-that-has-mailbox-g

#Exchange session for EOL
function EOLExchange-Session {
   Write-Host "Importing Exchange Scripting Module.....please wait a few seconds"
   Write-Host "NOTE: Login with your username@aklsj.com credentials for Office 365" -ForegroundColor red -BackgroundColor white
   pause
   $counter = 0
    while ($counter -lt 3) {
        try {
            $EOLPSSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell-liveid?DelegatedOrg=yalldontneedtoknow.com -Authentication Basic -AllowRedirection -Credential $UserCredential -ea stop
            write-host "success"
            $counter = 10
            }
        catch {
            write-host "failed"
            $counter++
            if ($counter -ge 3) {
                print "Too many attempts"
                exit
            }
        }
    }
   Import-PSSession $EOLPSSession -AllowClobber -DisableNameChecking -CommandName Get-Mailbox, Set-Mailbox


   $SessionID = $EOLPSSession.InstanceId
   Write-Host "-------------Instance ID = " $PSSession.InstanceId
   Write-Host "-------------Exchange-Session ID = " $SessionID
   $SessionID
}


#Exchange session for On-Prem
function OPExchange-Session {
   add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction Stop
   #Write-Host "Importing Exchange Scripting Module.....please wait a few seconds"
   #Connect to Exchange using Remote Shell <-- allows Exchange commands in this script
   $OPPSSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://mindyabusiness.com/PowerShell/ -Authentication Kerberos -AllowRedirection
   Import-PSSession $OPPSSession -AllowClobber -DisableNameChecking -CommandName Get-RemoteMailbox, Set-RemoteMailbox

   $SessionID = $OPPSSession.InstanceId
   #Write-Host "-------------Instance ID = "$PSSession.InstanceId
   #Write-Host "-------------Exchange-Session ID = "$SessionID
   $SessionID
}

Function End-Script($SessionID, $f_runtype) {
   Write-Host "Log File: $LogFile"
   Write-Host ""
   if ($SessionID -ne $null) {
      $s = Get-PSSession -InstanceId $SessionID
      Remove-PSSession -Session $s
  }

   if((Get-Content $LogFile) -eq $Null) {
    Remove-Item $LogFile
    } else {
    #Set Log File to Read Only
    Set-ItemProperty -Path $LogFile -Name IsReadOnly -Value $true
  }

   Write-Host "Script Complete" -ForegroundColor Gray
   Read-Host "Press enter to close the script"
   exit
}

Function SyncADConnect {
    $s = New-PSSession -computerName server
    Invoke-Command -Session $s -Scriptblock {Start-ADSyncSyncCycle -PolicyType Delta}
    Remove-PSSession $s
    End-Script
    }


#Removes any PSSessions before running
Get-PSSession | Remove-PSSession

#Find current path script is executing from
$ScriptPath = $PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
$ScriptPath = $ScriptPath + "\"

#Setup Log File
$LogPath = $ScriptPath + "Logs\"
$LogFilename = "SetExchangeGUID_$((Get-Date).ToString('yyyy-MM-dd_hh-mm-ss')).log"
$LogFile = $LogPath + $LogFilename
New-Item -Path "$LogFile" -ItemType File

Write-Host "Checking Domain Admin Permissions...."
$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$WindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($CurrentUser)

#Make sure user is a domain admin
if(!($WindowsPrincipal.IsInRole("Domain Admins")))
{
   Write-Host "You must be logged in as a Domain Admin to run this script" -ForegroundColor Red
   End-Script
}  else  {
   Write-Host "Domain Admin permissions detected, please wait....."
}


$today = Get-Date -Format yyyy-MM-dd_hh-mm-ss
$msg = "Run on " + $today + ". Run by " + $env:username
$msg | out-file $LogFile -Append

#Clear-Host

$CloudMailbox = Read-Host "Enter the identity of the cloud mailbox"

Write-Host "Connecting to EOL"
EOLExchange-Session
$SessionID = $EOLPSSession.InstanceId
Write-Host $SessionID
#Fetches EOL ExchangeGUID and trims to just the GUID
$TempCloudGUID = Get-Mailbox $CloudMailbox | Format-List ExchangeGUID | Out-String
$CloudGUID = $TempOnPremGUID.Substring(19).Trim()
#Clear-Host
Write-Host "The EOL GUID is $CloudGUID"
pause

Write-Host "Connecting to On-Prem"
OPExchange-Session

#Fetches ExchangeGUID and trims to just the GUID
$TempOnPremGUID = Get-RemoteMailbox $CloudMailbox | Format-List ExchangeGUID | Out-String
$OnPremGUID = $TempOnPremGUID.Substring(19).Trim()
#Checks if GUID is all zeros
#$ZeroGUID = "00000000-0000-0000-0000-000000000000"
#if ($OnPremGUID -eq $ZeroGUID) {
    #Write-Host "The value isn't stamped on the on-premises remote mailbox. Ending script"
    #End-Script
    #} else {
    #Write-Host $CloudMailbox "On-prem GUID is" $OnPremGUID
    #}

#Clear-Host
Write-Host "EOL GUID is $CloudGUID"
Write-Host "On-prem GUID is $OnPremGUID"
if ($CloudGUID -eq $OnPremGUID) {
    Write-Host "Exchange GUIDs already match, ending script."
    End-Script
    } else {
    $confirmation = Read-Host "The GUIDs are different, would you like to set the EOL GUID to be the same as On-Prem?"
    if ($confirmation -eq 'y') {
    Set-RemoteMailbox $CloudMailbox -ExchangeGUID $CloudGUID
    $msg = "$CloudMailbox has been changed to use $CloudGUID in EOL and On-Prem"
    $msg | out-file $LogFile -Append
    Write-Host "GUID for $CloudMailbox has been set. Syncing ADSyncClcye and ending script"
    Get-PSSession | Remove-PSSession
    SyncADConnect
    }
    else {End-Script}
}

Solution

  • No reason to do this from scratch. There are already tools/addons to do this for you.

    See these:

    Connect to all Office 365 Services PowerShell (Supports MFA too)

    Using our All-in-One PowerShell script, you can connect to all Office 365 Services using a single cmdlet. It supports both MFA and non-MFA account -Exchange Online -Azure AD -SharePoint Online -Skype for Business Online -Security & Compliance Center -Teams

    https://gallery.technet.microsoft.com/PowerShell-Script-to-4081ec0f/file/225256/1/ConnectO365Services.ps1

    https://blog.rmilne.ca/2015/02/02/using-exchange-powershell-remoting-with-integrated-scripting-environmentise

    https://jaapwesselius.com/2013/07/21/ise-remote-powershell-and-exchange-2013

    Adding Exchange Shell items to PowerShell ISE

    # in the Microsoft.PowerShellISE_profile.ps1 file, add the following contents:
    
    $psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add(
        "Connect to Exchange @ Contoso", {
            $ExSession  = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri 'http://exserver.contoso.com/PowerShell/' -Authentication Kerberos
            Import-PSSession $ExSession
        },
        "Control+Alt+1"
    )
    $psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add(
        "Connect to Exchange On-Premise", {
            Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
            . $env:ExchangeInstallPath\bin\RemoteExchange.ps1
            Connect-ExchangeServer –auto
                },
        "Control+Alt+2"
    )
    $psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add(
        "Connect to Exchange Online", {
            $o365Cred    = Get-Credential
            $o365Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri 'https://ps.outlook.com/powershell/' -Credential $o365Cred -Authentication Basic -AllowRedirection
            Import-PSSession $o365Session
        },
        "Control+Alt+3"
    )
    

    As for this...

    Get-PSSession | Remove-PSSession
    

    ... though it should work, I've often had this be a bit quirky, with forcing a loop.

    Get-PSSession | ForEach {Remove-PSSession -Id $PSItem.Id}