≡ Menu

Creating Scheduled Tasks for Exchange 2010 PowerShell Scripts

The process for scheduling Exchange 2010 PowerShell scripts with Windows Task Scheduler is different that what you may be used to in Exchange 2007. This is because Exchange 2010 uses PowerShell remoting for Exchange Management Shell administration. In this post I’ll go over how you can schedule PowerShell scripts for Exchange 2010 tasks.

Here are a few things you’ll want to take note of before getting started.

  • Tasks can be scheduled with or without the Exchange tools installed – since all PowerShell management is done via remoting, we can schedule the tasks to run on a workstation, or on an Exchange server.
  • Script signing – as a best practice, you may want to consider signing your scripts.
  • Execution Policy – the PowerShell execution policy is set to remotesigned automatically when you install Exchange. You may need to set your execution policy if you’ll be scheduling tasks to run from a machine without the Exchange tools installed.

PowerShell Command Syntax for Scheduling Tasks on a Machine with the Exchange Management Tools Installed

The following command syntax is what you’ll want to use to schedule your task. You need to tell PowerShell to load the Exchange Management Shell environment before executing your script. This will give you access to all of the cmdlets, variables and functions that are loaded with Exchange Management Shell. To schedule a .ps1 script to move mailboxes, the syntax would look something like this:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command “. ‘C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1′; Connect-ExchangeServer -auto; c:\Scripts\MoveMailboxes.ps1″

As you can see in the example, we’re using PowerShell code inside the command parameter. If you don’t want to use a .ps1 script you can embed your code within this parameter. Separate each line of PowerShell code using a semi colon. You might find this method useful for short scripts or one-liners. For example, say I want to schedule some mailbox moves from one DAG database to another, the syntax might look like this:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command “. ‘C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1′; Connect-ExchangeServer -auto; Get-Mailbox -Database DAGDB1 | New-MoveRequest -TargetDatabase DAGDB2″

These examples assume you used the default installation path for Exchange 2010; you may need to modify these commands to match your configuration.

PowerShell Command Syntax for Scheduling Tasks on a Machine Without the Exchange Management Tools Installed

To schedule PowerShell scripts we don’t actually need the Exchange tools installed, all we need is PowerShell v2. We can use implicit remoting to import the Exchange Management Shell cmdlets from a specific server. Take a look at the syntax:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command “$s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://fab-ex2.fabrikam.local/PowerShell/ -Authentication Kerberos ; Import-PSSession $s ; Get-Mailbox -Database DB1 | New-MoveRequest -TargetDatabase DB2″

This is very similar to the previous example as we specify all of our code within the command parameter. This time we create a new PSSession, import the PSSession, and then perform the mailbox move.

Scheduling a Task

Now that we’ve got the syntax figured out, we’re ready to schedule a PowerShell task using the Windows Task Scheduler. In this example we’ll schedule a task to do a mailbox move after hours, we’ll do this from the Exchange server.

First, start the task scheduler and create a new basic task.

Give your task a name, in this example we’ll name it “Move Mailbox”, click next.

In this example, we are just scheduling a mailbox move, so we’ll choose “One time”. If you have a script that needs to run daily then adjust the schedule accordingly.

Select the date and time you want to run the script and click next.

Select “Start a program” and click next.

Now paste the entire command into the “Program/Script” field and click next.

The task scheduler will ask if you want to run PowerShell.exe with the arguments specified. Verify that the syntax is correct and click yes.

That will bring you to the last screen, click finish.

There you go, you now have an Exchange PowerShell task scheduled to run.

If you have User Account Control (UAC) enabled, you may need to enable the option to Run with highest privileges in the properties of the scheduled task. Also, you will probably want to enable the option to Run whether user is logged on or not in the properties of the scheduled task.

22 comments… add one

  • Coco August 2, 2010, 1:58 pm

    Great post! Exactly what I was looking for. But how do you script (w/ task scheduler) 2007 to 2010 mbx moves? If I can, I’d like to use the .\movemailbox.ps1 script.

  • Mike Pfeiffer August 5, 2010, 1:21 pm

    Hi Coco, thanks. Are you talking about the built-in movemailbox.ps1 in the Scripts directory? If so, something like this should work:

    C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command “. ‘C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1′; Connect-ExchangeServer -auto;. ‘C:\Program Files\Microsoft\Exchange Server\V14\scripts\MoveMailbox.ps1′ -Identity administrator -TargetDatabase MB1″

  • Matthew March 29, 2011, 11:26 am

    Hi Mike,

    Thank you for writing this article, it certainly helps explain what I’ve been seeing. I am having an issue still, though, when I try to select to “Run whether user is logged in or not.” My task seems to hang. Using just the basic task creation wizard, this seems to work, as well as running the command below from CMD directly.

    The syntax I am using for the task is:
    “C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe” -command “. ‘P:\Exchange2010BINs\bin\RemoteExchange.ps1′; Connect-ExchangeServer -auto; C:\MoveReport\MailMoveReport.ps1″

    My script gets move request statistics, converts it to html, and creates a file on a remote web server.

    Do you have any ideas why this might be happening? I’ll keep testing and report back if I find something.

    Thanks

  • Matthew March 29, 2011, 11:35 am

    Well now I feel a little slow–just had to check the box “Run with highest privileges”.

  • Mike Pfeiffer March 29, 2011, 12:17 pm

    Gotcha…glad you got it working. Thanks Matthew.

  • Sandip June 3, 2011, 9:53 am

    Great post ….really saved my JOB….

  • Mike Pfeiffer June 3, 2011, 10:13 am

    Awesome :)

  • md88dg June 7, 2011, 2:07 am

    year graet

    thanks for this post, it will save me a lot of time

  • Mike Pfeiffer June 7, 2011, 9:53 am

    Great! Glad it helped.

  • Jonas July 29, 2011, 5:23 am

    Hi Mike – great stuff. Helped me a lot figuring out the syntax of the scheduled task that wasn’t running correctly..

    Just a quick question – can you explain period after the -command?
    -command “. ‘C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1′

    Will follow you on twitter, seems to be a very interesting blog you have here :)

    -Jonas, Denmark

  • Mike Pfeiffer August 1, 2011, 9:20 am

    Yes, that is the dot operator, used for dot sourcing a script. This runs a script so that the items in the script are part of the calling scope. For example, inside the RemoteExchange.ps1 script are several functions. Dotting this script first allows you to later call these functions.

  • Javier August 18, 2011, 1:30 am

    Hello, I have followed your advice on scheduling Exchange scripts. However for me it only works with the default administrator if I want to set “Run whether user is logged on or not”. If I do it with a service account (local admin, exchange org admin) it works only when:

    -You run the script for an interactive session of the user or a runas cmd
    -You set the Task as “Run only when the user is logged on” (and the user is logged on)

    If I run the Task as “Run whether user is logged on or not” and the user is not logged on, I get an error on the connection command (and the task hangs waiting for an answer). The transcript is as follows:

    Transcript started, output file is C:\scripts\informes\pruebasconexion.Log.txt

    Welcome to the Exchange Management Shell!

    Full list of cmdlets: Get-Command
    Only Exchange cmdlets: Get-ExCommand
    Cmdlets that match a specific string: Help **
    Get general help: Help
    Get help for a cmdlet: Help or -?
    Show quick reference guide: QuickRef
    Exchange team blog: Get-ExBlog
    Show full output for a command: | Format-List

    Tip of the day #31:

    Tab completion reduces the number of keystrokes required to complete a cmdlet. Just press the TAB key to complete the cmdlet you are typing. Tab completion kicks in whenever there is a hyphen (-) in the input. For example:

    Get-Send

    should complete to Get-SendConnector. You can even use wildcards, such as:

    Get-U*P*

    Pressing the TAB key when you enter this command cycles through all cmdlets that match the expression, such as the Unified Messaging Mailbox policy cmdlets.

    WARNING: The service () isn’t running. Connecting to remote Powershell requires this service to be running.
    VERBOSE: Connecting to CAS01.XXX.es
    An internal error occurred.
    + CategoryInfo : InvalidArgument: (http://cas01.XX…Ver=14.1.218.15:Uri) [], PSInvalidOperationException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

    VERBOSE: Connecting to CAS02.XXX.es
    An internal error occurred.
    + CategoryInfo : InvalidArgument: (http://cas02.XX..Ver=14.1.218.15:Uri) [], PSInvalidOperationException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

    WARNING: The service () isn’t running. Connecting to remote Powershell requires this service to be running.

    VERBOSE: Connecting to MBX02.XXX.es
    An internal error occurred.
    + CategoryInfo : InvalidArgument: (http://mbx02.XX…Ver=14.1.218.15:Uri) [], PSInvalidOperationException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

    VERBOSE: Connecting to CAS01.XXX.es
    An internal error occurred.
    + CategoryInfo : InvalidArgument: (http://cas01.XX…Ver=14.1.218.15:Uri) [], PSInvalidOperationException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

    VERBOSE: Connecting to CAS02.XXX.es
    An internal error occurred.
    + CategoryInfo : InvalidArgument: (http://cas02.XX…Ver=14.1.218.15:Uri) [], PSInvalidOperationException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

    WARNING: The service () isn’t running. Connecting to remote Powershell requires this service to be running.
    VERBOSE: Connecting to MBX02.XXX.es
    An internal error occurred.
    + CategoryInfo : InvalidArgument: (http://mbx02.XX…Ver=14.1.218.15:Uri) [], PSInvalidOperationException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

    Failed to connect to an Exchange server in the current site.
    Enter the server FQDN where you want to connect.:

    Do you know what’s missing? The error message refers to a () service, but I have no clue of which service can be needed and it is working only when a session is opened. The task is running with higher privileges.

    The command I run is

    C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command “. ‘c:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1′;c:\scripts\informes\estado_db_dag.ps1″

  • Javier August 19, 2011, 12:30 am

    Update:

    The problema had to do with the service user. I deleted the service user’s profile on the server and the task without a user session began to work.

  • Darren September 2, 2011, 6:22 am

    Hello,
    This script has been very useful for me moving from Exchange 2003 to 2010, however I’ve also witnessed the same problem some users have had with a blank file being generated and sent to my e-mail. I’ve checked the settings in regards to “Run whether the user is logged in or not” and “Run with Highest privileges”. If I run . ‘d:\dbreport.ps1′ from the EMS it works fine. Any help would be appreciated as this is a very useful script I would love to automate. Thank you

    C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command “. ‘C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1′; Connect-ExchangeServer -auto;. ‘d:\dbreport.ps1′”

  • Bernd Webster September 2, 2011, 1:59 pm

    I´m using your script, but I still can see the:

    - powershell.exe
    - taskeng.exe
    - conhost.exe

    In the taskmanager. It seamed they where not closed after the comand was running. How can we also close these tasks?

  • Brett Callegari March 29, 2012, 7:41 am

    Mike this is a great post. I did run into a few issues with my task.
    C:\Windows\system32\windowspowershell\v1.0\powershell.exe-command “. ‘e:\program files\microsoft\exchange server\v14\bin\remoteexchange.ps1′; connect-exchangeserver -auto; resume-mailboxdatabasecopy -identity ‘mailbox databasename\exchangeservername’” The quotes drove me crazy, All my databases have more than one word for database names. watch those single quotes in the identity. Yes , there is a single and then double quote at the end of this command. MY thanks to Jorge for helping me figure this out.

  • Nitin T. Kotak May 9, 2012, 8:27 am

    Following the steps shown by Mike I was able to schedule the task and successfully run it on a command prompt (not powershell or EMS) on an Interactive basis. However, my scheduled task was getting stuck in “Running” state.

    I searched the web for others who have experienced this issue with scheduled tasks, and what I found is that there could be a few reasons why this might happen. Solution in my case was adding -NonInteractive switch before the -command parameter.

    It may be worth trying to add the noninteractive switch and seeing.

  • Nathan Dublya May 16, 2012, 11:07 pm

    I’ve been using this to run two scheduled tasks for Exchange – One is to get the amount of free space available on our Databases, and the other is to check the content index state of all the databases. One of them I created using the method of putting the powershell code inside the actual command. The second one was pointing to a script. I found that I had to put in an extra period or ‘.’ as well as ” quote the path the script lived in front of the path that runs the script as below (in the ‘add arguments’ filed):

    -command “. ‘C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1′; Connect-ExchangeServer -auto;.’C:\Tasks\Exchange Monitoring\ContentIndex-State.ps1′”

    The task would not run no matter what combination I tried until doing this.. Thought it might help anyone else out that could be struggling

  • Joel September 10, 2012, 11:13 am

    Excelente aporte.

  • Alan July 12, 2013, 7:50 am

    Any idea about my problem please?

    I have a regular, non-admin user at Windows level who is an Exchange View Only Admin and a batch file containing:
    C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command “. ‘C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1′; Connect-ExchangeServer -auto; get-mailbox testuser”

    I have a Win 2008 R2 server with Exchange 2010 tools installed. If I logon as the regular user and run the batch file, it works without any prompts or errors.

    BUT if I schedule it as a task, it runs but the Connect-ExchangeServer -auto part gives an “internal error” then, PSInvalidOperation then finally “CreateRemoteRunSpace” exception and “cannot connect to an Exchange server in the site”.

    I can reproduce this on different systems with default installations. Any idea what the difference is? I’ve tried switching off UAC, making the user a local or domain admin in Windows and Org admin in Exchange, even Set-PSSessionConfiguration -Name Microsoft.PowerShell -showSecurityDescriptorUI and adding the account there, etc.

    Hope you can help – I just want to run a scheduled task as a regular user that only has view only rights.

  • Mike Pfeiffer July 16, 2013, 5:20 pm

    Well, it sounds like you ruled out the permissions issue, so it sounds like a problem with the scheduled task itself. Are you sure its running as the account that it is supposed to? Make sure you checked “Run with highest priviledges”. ALso, does it work if you use the implicit remoting method? For example:

    C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command “$s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://fab-ex2.fabrikam.local/PowerShell/ ; Import-PSSession $s ; Get-Mailbox testuser”

    Note: don’t copy and paste this code…type it from scratch

  • Alan July 29, 2013, 4:03 am

    It only runs if I use this kind of syntax:

    PowerShell.exe -PSConsoleFile “C:\Program Files\Microsoft\Exchange Server\v14\Bin\ExShell.Psc1″ -Command “Get-Mailbox testUser”

    I also had to use something like that in Exchange 2007.
    Any problems doing that?

    Thx.

Leave a Comment