Passing active powershell Session to background jobs - powershell

I am writing a powershell script to manipulate Exchange Online mailboxes.
I want this script to run with background jobs in parallel, so I'm trying to use PoshRSJobs (https://github.com/proxb/PoshRSJob) to create the jobs.
My code is:
Connect-ExchangeOnline -Credentials ...
Start-RSJob -ModulesToImport ExchangeOnlineManagement -Throttle $ProcesosConcurrentes -InputObject $jobs -ScriptBlock {
./migra_buzon.ps1 ...
}
Where:
$jobs is an arraylist where I have the parameter of the mailboxes I want to operate with
migra_buzon.ps1 is another powershell scripts that operates over one specified mailbox
The problem I have when I run this way is that in the jobs I have the error:
The term 'Add-MailboxPermission' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
Although other commands like Get-EXOMailbox are working correctly.
Looking for help I found that the problem can be related with the session, so I changed my code to:
Connect-ExchangeOnline -Credentials ...
Start-RSJob -ModulesToImport ExchangeOnlineManagement -Throttle $ProcesosConcurrentes -InputObject $jobs -ScriptBlock {
$o365session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://outlook.office365.com/powershell-liveid" -Credential $(Import-Clixml $Using:ExchangeCredentials) -Authentication "Basic" -AllowRedirection
Import-PSSession $o365Session -CommandName #('Add-MailboxPermission', 'Get-MailboxPermission')
./migra_buzon.ps1 ...
}
In this case, the problem I have is with the Exchange connection. After running a few jobs I'm getting the error:
[outlook.office365.com] Processing data from remote server outlook.office365.com failed with the following error message: Client did not get proper response from server. For more information, see the about_Remote_Troubleshooting Help topic.
Cannot validate argument on parameter 'Session'. The argument is null. Provide a valid value for the argument, and then try running the command again.
So my question is, what is the right way to run background jobs sharing the connection got in the main process?
Thanks
PS: I first tried to run jobs with Start-Job, but with this the problem is that each background job needs its own connection, so I got and maximum number of connections exceeded. And this is the reason I changed my code to Start-RSJob

It appears that you are hitting Exchange Online throttling limits.
If that indeed the case, you can try the following method.
How to relax PowerShell throttling
There is a relatively new customer facing way to increase or update PowerShell Throttling Policies.
Go to Microsoft 365 admin center.
Validate that you are logged in with the user that has the correct role assignment.
Click on the Need Help? Widget in the bottom right corner
Graphical user interface
Type Exchange PowerShell throttling in the search box and select “Temporarily update throttling policies for a migration”. Keep in mind that this is only applicable for 90 days. After 90 days, the throttles will return to back to the default values for that tenant.

MachSol offers Tenant management using a job engine, that allows you to do multiple operations using front-end and let the jobs handler take care of processing in background. You can give it a try:
https://www.machsol.com/machpanel-automation-for-microsoft-CSP-partners/

Related

Double-Hop Errors when running Skype for Business Cmdlets

I am attempting to automate the Skype for Business Server installation process in Powershell, I have a script that remotes into specified machines and begins preparing them as Front-End servers. The problem lies when certain SfB cmdlets (SfB commands are all of the form "verb-Cs...", ex. Get-CsUser or Get-CsPool) are run in remote sessions, they throw the double-hop error:
Exception: Active Directory error "-2147016672" occurred while searching for domain controllers in domain...
This is after running Enable-CsComputer, which enables the computer's role-based off its definition in the topology (topology was published successfully). The user object is in all required groups (RTCUniversalServerAdmins, Schema Admins, CsAdministrators & Local Admin rights on all SfB Servers). Oddly enough, the command 'Import-CsConfiguration -localstore" does not throw errors, and it's in the same remote session. There may be other local or domain groups that I need to be in, but I cannot pinpoint exactly which and have not seen them documented in the Skype build guides. Skype commands that have parameters to specify targets or just pull data, such as Get-CsPool or Get-CsAdForest, do not have errors because they are run in the local scope. The Enable-CsComputer has no parameter for the computer name, it has to be executed from that machine itself.
Enabling CredSSP delegation on each server is not an option, and I'm not understanding why there is a "second hop" in this command! If the second hop was a resource on a file server or database, that would make sense, and be easy to solve, but in this case, I can't track it. Can anyone tell me what I may be missing?
Here's a code sample to try and illustrate. From the jumbox I get the pool data to create an array, and a session is opened to each machine:
$ServerArray =get-cspool -identity $poolName
$i=0
$SessionArray = #{}
foreach($server in $ServerArray.Computers){$SessionArray[$i] = new-PsSession -ComputerName $server}
foreach($session in $SessionArray.values){
invoke-Command -session $session -scriptBlock {
#remote commands:
import-csConfiguration -<config file path> -localstore; #no errors
enable-CsReplica; #no errors
enable-cscomputer; #double hop error here
}}
If I log into that machine and run the same command, it executes fine but the intention of the project is to automate it on an arbitrary number of machines.
It looks like it's just trying to authenticate to a domain controller, which is reasonable. You'll have to approach this like any other double-hop issue.
Microsoft has an article dedicated to the double hop issue, and has a few solutions other than CredSSP that you can look at: Making the second hop in PowerShell Remoting

vNext Work Around for Second Hop Issue on NonDomain Machines

I've asked the Microsoft Developer Community this question but I haven't had much success.
I am trying to create some automation tests with a vNext Build Definition in which the build agent RemotePSSession into a non-domain virtual machine (the test machine) and runs a batch file that can take several arguments. This batch file may read (installer files) or write (reports) to a network share that is on the domain. The issue that I am coming across is the second hop issue. Here is an article about it: https://blogs.technet.microsoft.com/ashleymcglone/2016/08/30/powershell-remoting-kerberos-double-hop-solved-securely/
In my instance, the PowerShell Remote Session is not able to pass the credentials we have authenticated previously in the test machine to access the network share’s resources. We have tried using CredSSP authentication on both the agent and the test machine to enable access but that has failed. The Net Use and other commands which call domain resources have also failed. We’ve even tried modifying the custom task PowerShell on Target Machines task and did not have much luck with it.
From what we have discovered is that there is no way to access the domain network shares with RemotePSSession with the following topology: Server A (which is in the domain or workgroup) ⇒ RemotePSSession + CredSSP into Server B (which is non-domain), using a local admin Server B account ⇒ Calls the network shares, with Net Use using some domain account.
It seems that the second hop only works for domain-joined machines (we have been testing it CredSSP using as well).
Let us know if there is a solution or workaround that we can implement.
Their response was >> If you can make sure the method is correct and the issue is caused by DevOps, we will be happy to help you with your issues about DevOps. Here are some documents might be helpful: https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/ps-remoting-second-hop?view=powershell-6.
I've looked at this documentation before and I haven't had much success, does anyone else have any suggestions?
Here is a code snippet:
#serverA - local machine
#serverB - $remoteServer
#serverC - DFS namespace server
$session = New-PSSession -ComputerName $remoteServer -Credential $credential -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck) -Authentication Credssp
$scriptBlock_runFile = {
#Scenario 0 which works:
#ipconfig
#Scenario 1 which doesn't work:
#& dir \\contoso.com\departments\folder"
#Scenario 2 which doesn't work:
#& net use x: \\contoso.com\departments\folder /user:CONTOSO\user "password"
}
Invoke-Command -Session $session -ScriptBlock $scriptBlock_runFile

remote powershell script issue for adding IP address as relay - exchange 2010

firstly just to say my powershell skills are limited so please be gentle ;-)...
So I've built 4 or 5 runbooks using microsoft Orchestrator to essentially run some remote powershell scripts which do various simple exchange tasks, such as setting OutOfOffice reply, enabling mailboxes, creating shared mailboxes with various permissions etc. I had been using the same basic connection structure/method for these which works fine, ie
$ExchangeCAS = "<CASServerName>"
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://<CASServerNameFQDN>/PowerShell/
import-PSSession $Session
<script body with exchange cmdlets>
remove-PSSession $Session
However, I'm trying to create an additional runbook to automatically add IP addresses as relay to our 4 hub servers - its a pretty basic script (that I dug out/tweaked from internet) but its not working when run from Orchestrator. It does work fine when I run it from the Powershell ISE on the server that has the Exchange Tools installed, and the fact that the other exchange (similar) scripts that do work would at least rule out any permissions issues for the Orchestrator service account executing the script. For reference below is the full script I'm trying to run from Orchestrator as a .Net Activity and am testing using the powershell ISE on orchestrator server:-
$ExchangeCAS = "<ExCAS>"
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://<ExCASFQDN>/PowerShell/
import-PSSession $Session
# Get Receive Connectors to update
$listofIPs = Import-Csv \\<TargetSERVER>\d$\psscripts\MailboxRightsScript\scorch\AddIPlist.TXT
$recCons= Get-ReceiveConnector | Where {$_.Name -match"Anonymous Relay"}
ForEach ($recCon in $recCons)
{
Write-Host "Updating", $recCon.Identity
forEach($line in $listofIPs)
{
$recCon.RemoteIPRanges +=$line.IP
}
Set-ReceiveConnector $recCon -RemoteIPRanges $recCon.RemoteIPRanges
}
remove-PSSession $Session
The error I can see from the Orchestrator server ISE is as below:
Cannot process argument transformation on parameter 'Identity'. Cannot convert the "\Anonymous Relay" value of type "Deserialized.Microsoft.Exchange.Data.Directory.SystemConfiguration.ReceiveConnector" to
type "Microsoft.Exchange.Configuration.Tasks.ReceiveConnectorIdParameter".
From trawling through some articles it seems this is an issue with how data is passed between local and remote powershell and 'hydration' of objects. TBH a lot of the detail of those discussions is a bit over my head when it comes to powershell, so not wishing to be lazy would anyone be able to provide a powershell script solution based on what I was trying above which I can run as a .net activity from Orchestrator to add an IP address/addresses (prefer from input file) as relay. It would be good to know if the solution is easily modified to remove an address as relay aswell.
Any help much appreciated...
Use server distinguish name. It will work
Set-ReceiveConnector $recCon.DistinguishName -RemoteIPRanges $recCon.RemoteIPRanges

How to create a Powershell scipt to automatically connect to o365 and run as a schedlued task

I would like A PowerShell script to automatically connect to office 365 and to run as a scheduled task twice a day, THEN assign Reviewer permissions to new users if not possible then reviewer for all users. the reason being is because when a new user is created in outlook 365 their calendar permissions are set to free/busy.
i suggest you take a look at: OfficeDev/PnP - TimerJob
Shows how to create "remote timer job", which could be installed to be running as a WebJob to Windows Azure or scheduled to windows scheduler for on-premises deployment.
This is entirely possible, with the obvious downside that you'll need to store credentials for an account with permissions to edit all user calendars by default to run the script with.
There are two parts to the script that you'll require:
Connecting to Exchange Online
As shown here, connecting to Exchange Online is a very simple process.
Leaving the question of how to store credentials in a secure method out of scope of this question, this will result in a PowerShell session to the Exchange servers:
$UserCredential = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $Session
Selecting New Users
You'll then need to either select the new users (by passing them to this script, or scanning AD - this will depend on how you're creating your users - synced from AD or just created in-cloud), and apply the permission change to them. However...
Changing Default Permissions on Calendars
In this case, as I don't know how you're creating the new users, or how best to test that, I'm simply applying it to everyone. This will take far longer in a large environment, and is just a pretty bad idea.
Get-Mailbox -Filter {RecipientType -eq 'UserMailbox' -and IsShared -eq $false}| %{
Set-MailboxFolderPermissions -Identity "$($_.Alias):\Calendar" -User Default -AccessRights Reviewer
}
Finally, according to the original article, you should close the remote session.
Remove-PSSession $Session
Scheduled Tasks
After fixing the issue with credentials, you'll then want to save the script (ensuring that it complies with the Execution Policy on the system you'll be running it on), and create a new scheduled task to run it.
Configure a Scheduled Task as appropriate (in terms of triggers and conditions), and set the Action as Start a program, with that program being powershell.exe. Arguments should include -File C:\Path\to\Saved\Script.ps1 and any arguments (such as a file of new users).
Having said all of that, what you should actually do is change the sharing policy in 365, which will allow you to set the default permission for calendars.

Get status of a process started by Invoke-WmiMethod

New to PowerShell, but loving the fact that I can do so much so quickly so far :)
Anyways, I am starting a remote process in a PowerShell script thusly:
$compname = "MY-PC"
$myinstallcmd = "c:\install\myprog.exe /s"
$proc = Invoke-WmiMethod -class Win32_Process -name Create -ArgumentList ($myinstallcmd) -ComputerName $compname
On most of the PCs I've tried, the Invoke-WmiMethod cmdlet works fine, but on one PC, it's hanging. What I'm now looking to do is get the status of the running process, and if it's hung up, kill it and log the kill, and then move on.
I did find a possible method to do this in the post
Starting a process remotely in Powershell, getting %ERRORLEVEL% in Windows - however, when I try to do the Register-WmiEvent on the process $proc.ProcessId, I'm getting the dreaded 0x80070005 (E_ACCESSDENIED) error... I am running the PowerShell host as domain admin.
Can anyone please suggest a way that I can get a status on the process I've started, and be able to take an action based on the status?
Thanks!
Update: I guess you are missing remote system credentials:
Try passing the credentials to remote system using -Credential parameter. This takes a PSCredential Object and hence you can do something like:
$cred = Get-Credential
Register-WMIEvent -Credential $cred <and other parameters here>
See if any of the following resolves the access denied error:
0x80070005 (DCOM ACCESS_DENIED)
This error occurs when the connected user is not recognized or is restricted in some fashion by the remote server (for example, the user might be locked out). This happens most often when accounts are in different domains. Recent changes to WMI security can also cause this error to occur:
Blank passwords, formerly permitted, are not allowed in Windows XP and Windows Server 2003.
WMI does not allow asynchronous callbacks to a Windows 98 client. A call like SWbemServices.ExecNotificationQueryAsync from a Windows 98 computer to a Windows XP computer will result in an Access Denied error returned to the Windows 98 machine.
The DCOM configuration access setting might have been changed.
If the target computer is running Windows XP, the Forceguest value under the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa might be set to force the Guest account off (value is zero).
Source: http://technet.microsoft.com/en-us/library/ee692772.aspx