New-ExoPSSession error when using Connect-ExchangeOnline command in PowerShell - powershell

I am trying to connect to PowerShell using the Connect-ExchangeOnline command but I receive the following error. Any ideas?
New-ExoPSSession : .
At C:\Program Files\WindowsPowerShell\Modules\ExchangeOnlineManagement\1.0.1\ExchangeOnlineManagement.psm1:445 char:30
+ ... PSSession = New-ExoPSSession -ExchangeEnvironmentName $ExchangeEnviro ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [New-ExoPSSession], Exception
+ FullyQualifiedErrorId : System.Exception,Microsoft.Exchange.Management.ExoPowershellSnapin.NewExoPSSession

Please try to use the cmdlet as follows:
Connect-IPPSSession -PSSessionOption
$EXOSession = New-ExoPSSession -pssessionoption
Import-PSSession $EXOSession -Prefix EXO

Removing the security baseline from Intune and resyncing by rebooting fixed the issue in my case.

Here's a script that I use to connect. Please fill in your default username and make sure to run the prerequisites in the comments at the top (review first of course)
WMF 5.1
.Net 4.5
And if you're using this non-interactive you'll want to look up how to store your credentials securely and how to use those stored credentials, replacing the Get-Credential section with your configuration
# Requires: .Net 4.5, Windows Management Framework 5.1 (see https://learn.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/connect-to-exchange-online-powershell?view=exchange-ps )
#
# Run Once:
# Set-ExecutionPolicy RemoteSigned; Get-ExecutionPolicy
# Install-Module PowerShellGet -Force
# Install-Module –Name ExchangeOnlineManagement
#
# https://learn.microsoft.com/en-us/powershell/exchange/exchange-online/exchange-online-powershell-v2/exchange-online-powershell-v2?view=exchange-ps
$exo = New-Module -AsCustomObject -ScriptBlock {
$UserName = "Default.Username#domain"
$UserCredential = Get-Credential -message "Enter 365 admin credentials" -UserName $UserName
function IsConnected(){
try{
if (
#($(get-mailbox -resultsize 1 -WarningAction silentlycontinue)).count `
-eq
1
) {return $true}
}
catch {}
return $false
}
function Connect(){
$result = "Unfinished"
if ($this.IsConnected()) {
$result = "Success"
} else {
$UserCredential = $this.UserCredential
Connect-ExchangeOnline -Credential $UserCredential
if ($this.IsConnected()) {
$result = "Success"
} else {
$result = "Fail"
}
}
switch($result){
"Unfinished" {Write-Warning "`nAn unknown error occured in .Connect(), Appears to have ended while unfinished";break}
"Success" {Write-host "`nSuccessfully connected to Exchange 365";break}
"Fail" {Write-Warning "`nFailed to connect to Exchange 365";break}
default {write-warning "`nAn unknown error occured in .Connect(), result code unrecognized";break}
}
# old style
#$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
#Import-PSSession $Session -DisableNameChecking -AllowClobber
}
function ConnectMsol(){
Connect-MsolService -Credential $UserCredential
}
function Disconnect(){
Disconnect-ExchangeOnline
# old sytle
#Remove-PSSession $Session
}
function Cycle(){
$this.Disconnect()
$this.Connect()
}
Export-ModuleMember -Function * -Variable *
}
$exo.Connect()
#$exo.ConnectMsol()
<#
# --- Azure AD ---
# https://learn.microsoft.com/en-us/office365/enterprise/powershell/connect-to-office-365-powershell#connect-with-the-azure-active-directory-powershell-for-graph-module
# --- Azure AD ---
#>

The newest version of Exchange Online module requires PowerShell V7. As soon as I installed V7 it worked fine.
Per: https://learn.microsoft.com/en-us/powershell/exchange/exchange-online-powershell-v2?view=exchange-ps#install-and-maintain-the-exo-v2-module
EXO V2 module is supported in PowerShell 7.0.3 or later

I was able to resolve a similar issue by switching my default web browser in Windows 10 to the Chromium Edge browser. I brought up the login window once, then switched Firefox back to my default browser and it still worked.
PowerShell v7 is not required to use the ExchangeOnlineManagement module, but is an acceptable workaround. It uses the account logged into the default web browser for authentication, which wasn't an acceptable solution for me. It led me to switching the default browser, though, which resolved my initial problem.

Related

Powershell: Working as script, but not as a module

I have written a simple code to connect the console to different clients and different services with two switch options
First: select the customer/client
Second: select the service (Azure AD/Ex Online)
When I run this as a script, it works without any issues.
When I run this as a module, it still works to the point that when I select Exchange Online, it will login with the saved credentials and "import" some data.
But for example Get-Mailbox is no recognized command - only if I run this as a script - though the "connection" to O365 is alive. In this step I have to redo the Import-PSSession again to get those commands working.
Can somebody tell me what I've done or understood wrong, here?
Thanks.
<#
.SYNOPSIS
Easy connect to different O365 Modules
.DESCRIPTION
Use the different options to connect to O365: AzureAD, Exchange Online, etc.
.PARAMETER Client
Enter the client you are trying to connect to.
BUD (****)
MEN (****)
.PARAMETER Service
Enter the service you need.
Option 1: AAD (Azure AD)
Option 2: Exchange (Exchange Online)
.EXAMPLE
Connect-O365 -Client BUD
.NOTES
Written by: Daniel Leiner
Version: 1.2
Date: 05/07/2019
#>
param(
[parameter(mandatory=$false)][string]$Client,
[parameter(mandatory=$false)][string]$Service
)
if ([string]::IsNullOrEmpty($Client)) {
$Client = switch (Read-Host "Hello, which client you want to connect to?" `n "1) BUD "`n "2) Men" `n "3) Different"`n)
{
1 { "BUD"; break }
2 { "MEN"; break }
3 { "Unknown"; break }
default { "Inkorrekte Eingabe" }
}
}
If ($Client -eq "BUD")
{$Cred = Get-StoredCredential -User admin#************}
Elseif ($Client -eq "MEN")
{$Cred = Get-StoredCredential -User admin#*************}
Elseif ($Client -eq "Unknown")
{ $Cred = Get-Credential" }
if ([string]::isNullorEmpty($Service)) {
switch (Read-Host "Where do you want to connect to?" `n "a) AzureAD" `n "b) Exchange Online" `n)
{
a { $service = "AAD"; break }
b { $service = "Exchange"; break }
default { "Incorrect Input." }
}
}
if ($service -eq "AAD")
{ Connect-AzureAD -Credential $cred }
elseif ($service -eq "Exchange")
{ $global:worksession = New-PSSession -ConfigurationName Microsoft.Exchange -Credential $cred -ConnectionUri https://outlook.office365.com/powershell-liveid `
-Authentication Basic -AllowRedirection
Import-PSSession $global:worksession -AllowClobber -DisableNameChecking
}
}

Import-PSSession - throwing credentials-mask

I got a problem with a powershell-script used in our domain to create new users:
Helpdesk will call a .bat as administrator, this bat calls a script-file to automate the creation. In this script, two sessions are created and imported, to use the Exchange- and AD-cmdlets locally.
During/after the import a second/third credential-mask gets thrown, but clicking "cancel" will do nothin, the script will run through without any issues. Nevertheless this annoys the helpdesk..
When running the .ps1 directly from the ISE, the mask won't be shown. Also, when C&Ping the Create-/Import part of the script to a new file and calling it the same way as before also won't show these mask..
Here a part of the .ps1-file:
<#
.DESCRIPTION
Creates a new standard user
.NOTES
Requires : Exchange 2016 Remote Session
Req.OS Version : not tested
Req.PS Version : not tested
.EXAMPLE
Create-User.ps1 -datapath \\path\to\userdata.csv -credentialobject $cred
#>
Param (
[string]$datapath, <#Folder where the CSVs sit #>
[System.Management.Automation.CredentialAttribute()]$credentialobject = $null
)
#region SET global var definitions
$ErrorActionPreference = "Continue"
Start-Transcript -path $ScriptLogPath # | out-null
#endregion
#region SET var definitions
$userfile = "$datapath\userdata.txt"
$groupfile = "$datapath\groupdata.txt"
#Exchange
$MSXremotingserver = "exchangehostname"
$MSXdatabasenames = #("msx_db")
#AD
$domaincontroller = "dchostname"
$ADremotingserver = $domaincontroller
$BaseDN = "OU=Users,DC=domain,DC=local"
#endregion
#region Import Userdata
# CSV's are getting imported here - WORKING
#endregion
#region INIT Remotesession
#Get AD Creds / use given AD Creds
if (($credentialobject -ne $null) -and (($credentialobject.GetType()).name -eq "PSCredential")){
$UserCredential = $credentialobject
}else{
$UserCredential = Get-Credential
# Get credentials to create the remote-sessions. Seems to be working.
}
$MSXSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionURI http://$MSXremotingserver/powershell -Credential $UserCredential
echo "import..."
$null = Import-PSSession $MSXSession -AllowClobber -DisableNameChecking # | out-null
# After the import (Progress bars running through on top of the PS) another credential-mask appearing, "Cancel" makes the script run through without further errors.
echo "OK"
$ADSession = New-PSsession -Computername $ADremotingserver -Credential $UserCredential
Invoke-Command -Command {Import-Module ActiveDirectory -DisableNameChecking} -Session $ADSession # | out-null
echo "import..."
Import-PSSession -Session $ADSession -Module "ActiveDirectory" -Prefix Remote -AllowClobber -DisableNameChecking # | out-null
# After the import (Progress bars running through on top of the PS) another credential-mask appearing, "Cancel" makes the script run through without further errors.
echo "OK"
#AD-user already existing?
if ([bool](get-remoteaduser -LDAPFilter "(SamAccountName=$($userdata.Kuerzel))")){
#Throw custom error - AD-User bereits vorhanden!
}
#build Account...
# AD-user and Mailbox are created and configured. WORKING!
#endregion
#region END Script
Get-PSSession | Remove-PSSession
Stop-Transcript
Write-Host "Beende Skript..."
start-sleep -Seconds 3
exit 10000
#endregion
And here's how the .ps1 is being called:
%systemroot%\System32\WindowsPowerShell\v1.0\powershell.exe -executionpolicy bypass -file \\helpdeskserver\powershell_userdata$\Create-User.ps1 \\helpdeskserver\path\to\csv"
I don't know what to do. Tried many different versions of each command, tried piping the in/output, nothing will do..
Google doesn't seem to know that behaviour, neither anyone here on Stackoverflow..
Thanks for any tips and help, I'll apprechiate!
Regards, Ting3l
Edit: When starting the .bat-file without administrative rights (Or with right-click -> other user.. -> admin-account) the second/third credential-dialog won't appear, instead I get an "Index out of range"-exception.
Maybe it's unimportant, but you can try to exit the session by Exit-PSSession. After that use exit 1000. Becoaser when you use exit in the session it completes the session (wherein all code after will be ignored, but script will have successful completed)

Why is Powershell not importing the exchange Commandlets after removing all Pssession's and adding a new one?

Context
I created a little Powershell Script that lets you change between 2 Exchange Server (Pssession to the 2 servers).
In the Begin part of the script I remove all existing pssessions (it's on to the default Exchange 2010 server).
# Remove all Ps-Sesssions
Get-PSSession | Remove-PSSession
Then in the Process part I do this:
Process
{
# Choose Server:
# Default server
$server = "2010"
if ($ExchangeVersion -eq "2016") {
$server = "2217ex0010at01"
} elseif ($ExchangeVersion -eq "2010") {
$server = "2217exlimbx01"
} else {
Write-Host "Server wurde nicht gefunden, gibt 2010 oder 2016 ein"
}
# Add Pssession and import it
$s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$server/powershell
Import-PSSession $s -AllowClobber
}
The problem
When I start up powershell, it imports a pssession to the 2010 server. Everything is working fine. I have all commandlets like get-mailbox
But when I run the script like this Set-ExchangeServer -ExchangeVersion "2016" everything appears to be fine. But then when I try any exchange commandlet it won't exist.
What have I tried
I manually typed in the code I have in the script to import the session to 2016. And thats the weird part. When I'm doing it manually it works and I have all commandlets.
What could be the cause of this issue?
I did for myself simple functions to remove the previous exchange sessions, it might help you.
Probably you did'nt remove the tmp*... Module...
For On-Premise:
Function Remove-LocalExchangeShell
{
if ($LocalSession = Get-PSSession | ? {$_.ComputerName -match 'exchSvrName'}) {Remove-PSSession $LocalSession}
if ($TmpModule = Get-Module -Name tmp*) {Remove-Module $TmpModule}
}
For Office365:
Function Remove-365ExchangeShell
{
if ($365Session = Get-PSSession | ? {$_.ComputerName -match 'Outlook'}) {Remove-PSSession $365Session}
if ($TmpModule = Get-Module -Name tmp*) {Remove-Module $TmpModule}
}
Run the one you need before executing the New-PSSession
I think the root cause is a question of scope.
Try changing $s = to $global:s = so that the session is available outside of the script.

How to remotely delete an AD-Computer from Active Directory - Powershell

I am running Powershell on a remote computer that is not connected to the domain, does not have any modules and is running PS 2.0.
I want to contact the Active Directory of my domain, check if there is an entry for this computer and; if yes, delete that entry.
Checking the AD via ADSI for existance of the computer is easy. However the deleting does not work somehow.
Here is my code so far:
# Variables
$domain = "Test.com"
$Ldap = "LDAP://$domain"
$Global:AdsiSearcher = $Null
# Function to Delete PC
Function DeleteThisPc ()
{
$CurrentSearch = $Global:AdsiSearcher
$One = $CurrentSearch.FindOne()
$OPath = [adsi]$One.Path
$OPath.psbase.DeleteTree()
The Problem lies here. Even though $OPath is of type System.DirectoryServices.DirectoryEntry and the propertylist shows all properties, it does not allow me to delete the object.
Exception calling "DeleteTree" with "0" argument(s): "Logon failure:
unknown user name or bad password.
At C:\TEMP\Domjoin1.1.ps1:49 char:33 $OPath.psbase.DeleteTree <<<< ()
CategoryInfo: NotSpecified: (:) [], MethodInvocationException
FullyQualifiedErrorId : DotNetMethodException
Code:
# Function to get a ADSISearcher and set it to the global-AdsiSearcher
Function ConnectAD ()
{
$domain = new-object DirectoryServices.DirectoryEntry($Ldap,"$domain\Bob",'1234')
$filter = "(&(objectCategory=computer)(objectClass=computer)(cn=$ComputerName))"
$AdsiSearch = [adsisearcher]""
$AdsiSearch.SearchRoot = $domain
$AdsiSearch.Filter = $filter
$Global:AdsiSearcher = $AdsiSearch
}
# Main Function
Function Sub_Check-ADComputer()
{
ConnectAD
$CurSearch = $Global:AdsiSearcher.findOne()
if($CurSearch -ne $null)
{
DeleteThisPc
}
}
# Start
Sub_Check-ADComputer
Even though the issue seems to be obvious as the error states:
Logon failure: unknown user name or bad password.
The username and password is the same that I use to get the object from the AD in the first place. So it does work - do I somehow have to give the credentials again when trying to deleteTree() ? I also gave the User FullControl on the OU that the object is stored in.
Edit:
When I do it on another machine with PS 3.0 I get a different Error message:
Exception calling "DeleteTree" with "0" argument(s): "Access is
denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))"
I found the problem.
When using invoke command the variables are not transmitted unless specified by -argumentlist. Another approach I discovered was the following, which is the one I am using now and which works like a charm.
$domain = "DOMAINNAME"
$AdUser = "$domain\JoinDom"
$AdPW = "PASSWORD"
$AdPass = convertto-securestring -string $AdPW -AsPlainText -Force
$AdCred = new-object -typename System.Management.Automation.PSCredential -argumentlist $AdUser,$AdPass
$ThisComputer = $Env:COMPUTERNAME
$RetValue = $true
Function CheckExist ()
{
$ErrorActionPreference = ‘SilentlyContinue’
$Ascriptblock = $ExecutionContext.InvokeCommand.NewScriptBlock("get-adcomputer $ThisComputer")
$Ret = Invoke-Command -ComputerName SERVERNAME -ScriptBlock $Ascriptblock -Credential $AdCred
$ErrorActionPreference = ‘Continue’
return $Ret
}
$ExistBefore = CheckExist
if($ExistBefore -ne $null)
{
$scriptblock = $ExecutionContext.InvokeCommand.NewScriptBlock("Remove-ADComputer $ThisComputer")
Invoke-Command -ComputerName SERVERNAME -ScriptBlock $scriptblock -Credential $AdCred
$ExistAfter = CheckExist
if($ExistAfter -ne $null){$RetValue = $false}
}
if($RetValue -ne $false)
{
Add-computer -domainname $domain -credential $Adcred -OUPath "OU=MyOU,DC=DOMAIN,DC=DE"
Restart-Computer -Force
}
If your domain controller runs Windows Server 2008 or higher you could leverage PowerShell sessions to avoid having to work with ADSI.
Just run the following command:
Enter-PSSession -ComputerName domaincontroller.test.com -Credential (Get-Credential)
Then run Import-Module ActiveDirectory to allow you to use Get-ADComputer and Remove-ADComputer.

rdesktop shell escaping issue

I'm trying to send this:
Get-WmiObject Win32_PNPEntity |Where{$_.DeviceID.StartsWith("PCI\VEN_10DE") -or $_.DeviceID.StartsWith("PCI\VEN_1002")}
over rdesktop like:
rdesktop -a8 209.** -u ** -p ** -s "cmd.exe /K powershell.exe Get-WmiObject Win32_PNPEntity |Where{\$_.DeviceID.StartsWith("PCI\VEN_10DE") -or $_.DeviceID.StartsWith("PCI\VEN_1002")}"
But windows' shell says:
'Where{$_.DeviceID.StartsWith' is not recognized as an internal or externa....
What am I doing wrong?
why not using powershell wmi remoting?
$cred = get-credential
Get-WmiObject Win32_PNPEntity -computerName MyRemoteComputerName - credential $cred |Where{$_.DeviceID.StartsWith("PCI\VEN_10DE") -or $_.DeviceID.StartsWith("PCI\VEN_1002")}
-credential are only needed if the actual user running powershell isn't administrator of remote machine.
Hi I needed to do some thing like this once so i wrote some code that can send any ps code to a remote computes and display the results in the ps window on your pc.
Just remember to enable powershell remoting on both pc's.
function remote-pscode ($ServerName,$UserName,$password,$PSCode)
{
$global:RemoteCode = $args[0]
Write-Host $RemoteCode
$conprops = (Get-Host).UI.RawUI
$buffsize = $conprops.BufferSize
$buffsize.Height = 800
$conprops.BufferSize= $buffsize
# Set the user name you would like to use for the connection
$global:RemoteUserName = $UserName
$global:RemoteServerName = $ServerName
# Set the password you would like to use for the connection
# Check to see if you have a file on you drive c:\cred.txt with a password to use in it,if you don't it will create one
# for you and ask you for the password you would like to use
$global:RemotePassword = convertto-securestring $password -AsPlainText -Force
$global:credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $RemoteUserName,$RemotePassword
#Create a connection to the remote computer , put a list of IPAddresses or Computer Names.
$global:session = new-PSSession -ComputerName $RemoteServerName -Credential $credentials
$ScriptBlock = $executioncontext.invokecommand.NewScriptBlock($RemoteCode)
invoke-command -Session $session -ScriptBlock $ScriptBlock
#Close the sessions that where created
$global:closesession = Get-PSSession
Remove-PSSession -Session $closesession
}
remote-pscode -ServerName "NameOfRemotePC" -UserName "UserName" -password "password" -PSCode "any powershell code you want to send to the remote pc"
Several things here: put your PS commands in a script block (or a script). Also, why don't you simply use wmic.exe ?