none
Using Start-Job with credentials RRS feed

  • Question

  • I'm trying to figure out how to run a background job using Start-Job against my Exchange environment to query large amounts of data. My code so far looks like the following...

    $global:usercred = Get-Credential
    $s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://ServerName.domain.com/PowerShell/ -Credential $global:usercred -Authentication Kerberos
    Import-Module (Import-PSSession $s -AllowClobber) -DisableNameChecking

    $sb = {
            $splat = @{
    	ConfigurationName = 'Microsoft.Exchange'
    	ConnectionUri	  = 'http://ServerName.doamin.com/PowerShell/'
    	AllowClobber	  = $true
    		}
    	$s = New-PSSession @splat -Credential $global:usercred -Authentication Kerberos
    	Import-PSSession $s
    		
    		(Get-MailboxDatabase | where { $_.MasterServerOrAvailabilityGroup -eq "DAG1" }).count
    	}
    
    	Start-Job -Name Job1 -ArgumentList $global:usercred -ScriptBlock $sb

    Ideally I would like to figure out how to pass credentials that have already been provided to the Start-Job command, it wouldn't scale very well if I had the user input their credentials every time I execute a job.


    • Edited by RK-33 Friday, April 12, 2019 4:38 PM
    • Moved by Bill_Stewart Wednesday, September 4, 2019 9:18 PM Abandoned
    Friday, April 12, 2019 4:17 PM

All replies

  • As I have noted elsewhere.  The job is running with the credentials so they will be used automatically if Kerberos is the protocol.  In a domain that is the default.  Exchange connections will use the current credentials so specifying them is unnecessary if the process is running with an account that is allowed access.

    To test this just run PowerShell as the user you want then run the New-PsSession command.

    $sb = {
            $splat = @{
    	ConfigurationName = 'Microsoft.Exchange'
    	ConnectionUri	  = 'http://ServerName.doamin.com/PowerShell/'
    	AllowClobber	  = $true
    }
    $s = New-PSSession @splat 

    A job with credentials works the same way.


    \_(ツ)_/

    Friday, April 12, 2019 6:20 PM
  • Ok, that is what I tried initially, however it didn't seem to work. When I run the exact code you have above and debug the program, I get errors, in this order...

    ERROR: A parameter cannot be found that matches parameter name 'AllowClobber'.
    ERROR: Cannot validate argument on parameter 'Session'. The argument is null. Provide a valid value for the argument, and then try running the command again.
    ERROR: The term 'Get-MailboxDatabase' is not recognized as the name of a cmdlet, function, script file, or operable program

    The third error is a result of the module not getting pulled down because the connection to Exchange never seems to be made, so disregard that one.
    Friday, April 12, 2019 6:26 PM
  • Remove AllowClobber.  I copied your original code incorrectly. Sorry.

    \_(ツ)_/

    Friday, April 12, 2019 6:41 PM
  • Ok, that allows the code to execute, but it doesn't appear that anything actually happens. When I debug the code it just runs right through it without actually doing anything. When I run Receive-Job 'Job1' afterwards it comes back with the following...

    ModuleType Version    Name                                ExportedCommands                                                                                               
    ---------- -------    ----                                ----------------                                                                                               
    Script     1.0        tmp_jjfu0hzn.3m5                    {Set-MailboxRegionalConfiguration, Search-MessageTrackingReport, Get-User, Set-DistributionGroup...}           
    The term 'Get-MailboxDatabase' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was 
    included, verify that the path is correct and try again.
    

    Almost looks like the scriptblock is still not even running. Here is my completed code that I am running...

    $button1_Click={
    	$sb = {
    		$splat = @{
    			ConfigurationName = 'Microsoft.Exchange'
    			ConnectionUri	  = 'http://ServerName.domain.com/PowerShell/'
    		}
    		$s = New-PSSession @splat
    		Import-PSSession $s -AllowClobber
    		
    		(Get-MailboxDatabase | where { $_.MasterServerOrAvailabilityGroup -eq "USADAG07" }).count
    	}
    	Start-Job -Name 'Job1' -ArgumentList $global:usercred -ScriptBlock $sb
    	
    	$Job1Results = Receive-Job 'Job1'
    	
    	$textbox1.Text = $Job1Results
    

    Sunday, April 14, 2019 9:21 PM
  • At a PS prompt enter the following:

    $button1_Click={
    	$sb = {
    		$splat = @{
    			ConfigurationName = 'Microsoft.Exchange'
    			ConnectionUri	  = 'http://ServerName.domain.com/PowerShell/'
    		}
    		$s = New-PSSession @splat
    		Import-PSSession $s -AllowClobber | Out-Null
    		
    		Get-MailboxDatabase 
    }
    Start-Job -Name 'Job1' -ArgumentList $global:usercred -ScriptBlock $sb
    	
    $Job1Results = Receive-Job 'Job1'
    

    Start small until you understand what your code is doing.  You have to understand what the error is.  The Get-MailboxDatabase is telling you that the module does not support that command. Perhaps the Exchange server does not support the commands you are looking for.

    The result tells us that you have authenticated correctly and the session has been imported with no errors.

    This is a new question and has nothing to do with your original issue.  YOU should now be asking in the Exchange forum for assistance with the various modules available for Exchange.


    \_(ツ)_/

    Sunday, April 14, 2019 10:26 PM
  • Ok, I actually got this working tonight. Here is the final code, I just modified the scriptblock a little bit.. I ran this 10 times in my environment, and it worked 10 out of 10..

    $global:usercred = Get-Credential
    
    $sb = {
    		$s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://ServerName.domain.com/PowerShell -Credential $global:usercred -Authentication Kerberos
                    Import-Module (Import-PSSession $s -AllowClobber) -DisableNameChecking
    		
    		(Get-MailboxDatabase | where { $_.MasterServerOrAvailabilityGroup -eq "USADAG07" }).count
    	}
    
    $Job1 = Start-Job -ArgumentList $global:usercred -ScriptBlock $sb
    $Output = $Job1 | Receive-Job -Wait

    One issue with this, it seems to be prompting me for credentials twice, once on the first line of Get-Credential (expected), but it seems to fire off another prompt when it gets inside the scriptblock somewhere, the 2nd prompt looks like this...

    Ideally I would like to enter credentials once, and pass them through in the ArgumentList, any idea where this is coming from?

    Also, I've noticed then when I do it this way, my form is no longer responsive, which kind of defeats the whole purpose of the idea. It looks like this is because I am using the -Wait parameter on Receive-Job..



    • Edited by RK-33 Monday, April 15, 2019 3:18 AM
    Monday, April 15, 2019 3:07 AM
  • Sorry but Get-MailboxDatabase is certainly a cmdlet for Exchange, and I assure you it can be ran from my servers. It's a native Exchange cmdlet and I run it a dozen times per day in reports. The error says it's not recognized as a cmdlet because the connection is never made to Exchange, so the Exchange cmdlets do not get pulled to down the local PC, since Exchange cmdlets are not native this is required, that error does not get thrown because the cmdlet doesn't exists or is not supported.

    Also, if you read my last comment on this thread, you can see it actually works when I modify the scriptblock and take out the @splat variable. I posted the latest code in that comment along with the progress.


    • Edited by RK-33 Monday, April 15, 2019 12:37 PM
    Monday, April 15, 2019 12:36 PM
  • I wound up taking a slightly different approach to this and using Powershell Studio's "Button - Start Job" control set. Below is my final code that is working (assume I have all the functions inserted correctly, too long to post them all).

    	$Job1 = @{
    		Name	  = 'Job1'
    		JobScript = {
    			Param ($global:usercred)
    			
    			$s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://ServerName.domain.com/PowerShell -Credential $global:usercred -Authentication Kerberos
    			Import-Module (Import-PSSession $s -AllowClobber -DisableNameChecking) -DisableNameChecking
    			
    			(Get-MailboxDatabase | where { $_.MasterServerOrAvailabilityGroup -eq "USADAG07" }).count			
    			for ($i = 0; $i -lt 50; $i++) { Start-Sleep -Milliseconds 100 }
    			
    		}
    		ArgumentList = $global:usercred
    		CompletedScript = {
    			Param ($Job)
    			$results = Receive-Job -Job $Job
    			$textbox1.Text = $results
    		}
    		UpdateScript = {
    			Param ($Job)
    			
    		}
    	}

    I do have one question with this approach though, if I were to assign the data to multiple variables within the JobScript block, what approach could I take to go about using them in the CompletedScript block? Example...

    $Job1 = @{
    		Name	  = 'Job1'
    		JobScript = {
    			Param ($global:usercred)
    			
    			$s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://ServerName.domain.com/PowerShell -Credential $global:usercred -Authentication Kerberos
    			Import-Module (Import-PSSession $s -AllowClobber -DisableNameChecking) -DisableNameChecking
    			
    			$DAG07 = (Get-MailboxDatabase | where { $_.MasterServerOrAvailabilityGroup -eq "USADAG07" }).count
                            $DAG08 = (Get-MailboxDatabase | where { $_.MasterServerOrAvailabilityGroup -eq "USADAG08" }).count	
    		
    			for ($i = 0; $i -lt 50; $i++) { Start-Sleep -Milliseconds 100 }
    			
    		}
    		ArgumentList = $global:usercred
    		CompletedScript = {
    			Param ($Job)
    			??????????
    		}
    		UpdateScript = {
    			Param ($Job)
    			
    		}
    	}


    • Edited by RK-33 Tuesday, April 16, 2019 2:11 AM
    Tuesday, April 16, 2019 2:10 AM
  • Your  solution is pretty much identical to the first one I gave you over on Sapien.

    You can only get results from a job if you output the results.  This means tha to get this in the completed block you must find a way to output the variable before the complete block.

    After any loop just output the collection variable.

    Actually this is quite unnecessary.  If you don't want any results in the update block then don't call receive-job.  Just call receive-job in the completed block.


    \_(ツ)_/

    Tuesday, April 16, 2019 2:36 AM
  • Your literally telling me the same thing that I am asking help for. Telling me to "find a way to output the variable" doesn't provide any insight to someone who is running into some trouble with that does it? I'm familiar with getting results this way...

    $Job8 = @{
    		Name	  = 'Job8'
    		JobScript = {
    			Param ($global:usercred)
    			
    			$s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://ServerName.domain.com/PowerShell -Credential $global:usercred -Authentication Kerberos
    			Import-Module (Import-PSSession $s -AllowClobber -DisableNameChecking) -DisableNameChecking
    			
    			(Get-MailboxDatabase | where { $_.MasterServerOrAvailabilityGroup -eq "USADAG14" }).count
    			
    			for ($i = 0; $i -lt 50; $i++) { Start-Sleep -Milliseconds 100 }
    			
    		}
    		ArgumentList = $global:usercred
    		CompletedScript = {
    			Param ($Job)
    			$results = Receive-Job -Job $Job
    			$textbox8.Text = $results

    $Results in this case gives me the result of the cmdlet in the JobScript. Where I am running into trouble is when I want to run multiple commands in the JobScript and bring back the results in a variable. I understand I need to find a way to do xyz, that is the whole reason I am here, what I'm looking for is some advice as a person who has been researching the topic and struggling to grasp this one. I've tried simplifying it, I've read multiple articles, and I've tried a few trial and error tactics, now I've decided to come here and ask for advice. Hence my post...

    Tuesday, April 16, 2019 4:59 PM
  • In your script you will take the variables saved in the script and add then to a hash and pass that back at the end.  This will be what returns in the Receive-Job as a property or the result object.  Now you will have both variables in this custom object.

    To see how this works just run your job at a CLI prompt and inspect the results.


    \_(ツ)_/

    Tuesday, April 16, 2019 6:27 PM