0

I have this powershell command to find the whitespace in each of my Exchange databases, however I cannot get it to run via batch.

Here is the shell command confirmed working:

 
get-mailboxdatabase -status | 
  select name, 
     @{Name="DataBaseSize";Expression={ "{0:N2} GB" -f (($_.DatabaseSize.ToBytes()) / 1gb) }},
     @{Name="AvailableNewMailboxSpace";Expression={ "{0:N2} GB" -f(($_.AvailableNewMailboxSpace.ToBytes()) / 1gb) }},
     @{Name="Difference";Expression={ "{0:N2} GB" -f (($_.DatabaseSize.ToBytes() - $_.AvailableNewMailboxSpace.ToBytes()) / 1gb) }}

Here is the batch to run the Shell command:


C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command ". 'D:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto;

I am thinking that the characters in the shell command are not cooperating with the batch and have tried "^" them where they fail. Any help would be appreciated. I am fairly new to both batch and powershell, so please use small words :)

NEW INFO: Hi thanks for your help. To answer your first question of why I am trying to do this with a batch is because this is just one of the steps I am trying to accomplish. I want this powershell command to output to a .txt doc so I can then run a FOR loop against it and write the parameters to an html file which will then be blat'ed daily to my IT team to monitor the growth on the whitespace. Also the error codes I am receiving are not related to your assumptions and I apologize for not including them. The error code I get is: Unexpected token ':N2' in expression or statement. When I remove the ":N2" from the command it then complains about the 'GB', and finally when I remove the "GB" it then complains about the term 'DataBaseSize'. So I will be trying your solutions here in the next few hours, I just wanted to say thanks and to let you know the errors I am seeing.

NEW ERRORS:

After I run it using Beavels suggestion I receive these errors:

C:\temp2>Whitespace.bat The term 'get-mailboxdatabase' is not recognized as the name of a cmdlet, funct ion, 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.

At C:\temp2\Whitespace.ps1:1 char:20

+ get-mailboxdatabase <<<<  -status |select name, @{Name="DataBaseSize";Express
ion={ "{0:N2} GB" -f (($_.DatabaseSize.ToBytes()) / 1gb) }}, @{Name="AvailableN
ewMailboxSpace";Expression={ "{0:N2} GB" -f(($_.AvailableNewMailboxSpace.ToByte
s()) / 1gb) }}, @{Name="Difference";Expression={ "{0:N2} GB" -f (($_.DatabaseSi
ze.ToBytes() - $_.AvailableNewMailboxSpace.ToBytes()) / 1gb) }}
+ CategoryInfo          : ObjectNotFound: (get-mailboxdatabase:String) [],
CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException

It is complaining about the term get-mailboxedatabase however this is a CDMLET. Ugh....

JOESPH

C:\temp2>. 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps 1' '.' is not recognized as an internal or external command, operable program or batch file.

C:\temp2>Connect-ExchangeServer -auto 'Connect-ExchangeServer' is not recognized as an internal or external command, operable program or batch file.

C:\temp2>$properties = @( '$properties' is not recognized as an internal or external command, operable program or batch file.

C:\temp2>"name" '"name"' is not recognized as an internal or external command, operable program or batch file. '{Name' is not recognized as an internal or external command, operable program or batch file. '{Name' is not recognized as an internal or external command, operable program or batch file. '{Name' is not recognized as an internal or external command, operable program or batch file.

C:\temp2># you might want to put this file on a file server somewhere '#' is not recognized as an internal or external command, operable program or batch file.

C:\temp2>$pathToFile = "\server\share\Some\Path\To\File.html" '$pathToFile' is not recognized as an internal or external command, operable program or batch file.

C:\temp2>$data = Get-mailboxdatabase -status | select $properties | sort-obj ect name | ConvertTo-Html | Set-Content $pathToFile - '$data' is not recognized as an internal or external command, operable program or batch file.

I may just take this Database offline and do a defrag to free up the space. Instead of trying to monitor it from this crazy idea.

Eddie.Brown
  • 1
  • 1
  • 1
  • 2

2 Answers2

2

First question I have is, why are you trying to do this via a batch file?

Option 1

If you are trying to get something that can be launched with a double-click from a file explorer, and you are using PowerShell 3.0, you can use the "Run with PowerShell" feature (run Get-Help about_Run_With_PowerShell from a PowerShell prompt). Just create a file with a .ps1 extension and set the contents like so:

. 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1';
Connect-ExchangeServer -auto;
get-mailboxdatabase -status | select name, @{Name="DataBaseSize";Expression={ "{0:N2} GB" -f (($_.DatabaseSize.ToBytes()) / 1gb) }},@{Name="AvailableNewMailboxSpace";Expression={ "{0:N2} GB" -f (($_.AvailableNewMailboxSpace.ToBytes()) / 1gb) }},@{Name="Difference";Expression={ "{0:N2} GB" -f (($_.DatabaseSize.ToBytes() - $_.AvailableNewMailboxSpace.ToBytes()) / 1gb) }}

Then just right click on the file and choose "Run with PowerShell"

Option 2

If you are trying to get a powershell script or command to be run by some software/system that does not like or understand PowerShell.

Now, with no actual error messages, or output to examine, I have to start making some assumptions.

When you run your batch script, do you get an error like:

. : File C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1
cannot be loaded because running scripts is disabled on this system. For more
information, see about_Execution_Policies at
http://go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:3
+ . 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1';
Conne ...
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : SecurityError: (:) [], PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess
Connect-ExchangeServer : The term 'Connect-ExchangeServer' 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.
At line:1 char:76
+ . 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1';
Conne ...
+
~~~~~
    + CategoryInfo          : ObjectNotFound: (Connect-ExchangeServer:String)
   [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

If so, then we do have some issues with execution policy. For more information on that, either use Get-Help about_Execution_Policies or go to the MS Technet page about execution policies.

My personal preference is to have the local machine scope set to the RemoteSigned execution policy, but that is just me.

Now, unless there is something missing from the contents of your batch file as provided, it looks almost identical to the target field of the Exchange Management Shell shortcut that is installed with the Exchange Management Tools. How are you passing the PowerShell command? Are you providing it as a commandline argument to your batch file, or is it part of the arguments hard-coded in the batch file? My suggestion would be to do either what foxdrive suggests, or to do something more like this:

Create a powershell script for whatever commands you need. Lets call this MdbWhitespace.ps1 and set the contents to your command.

Create your batch file. Let's call it RunExchPs.bat and set the contents to

@echo off
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noexit -command ". 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto; %1"

Basically, we are setting up the Exchange Remote Sessions (Get-Help about_PSSessions and Get-Help about_Remote) and connecting the same way the Exchange Management Shell does, then we are calling a script that you provide in the established environment.

I am assuming for the next step that your batch file and PS script are in the same directory, which is your current directory in an open command prompt, and run .\RunExchPs.bat .\MdbWhitepace.ps1.

As long as your execution policy is setup correctly to allow scripts to run, this will work perfectly. If you can't or don't want to permanently change the execution policy, you can set your batch file to change it for that session:

@echo off
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noexit -command "Set-ExecutionPolicy Bypass Process -Force; . 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto; %1"

Hope this helps.

EDITS IN RESPONSE TO COMMENTS

For the ConvertTo-Html that I mentioned in the comment,

You can do

$dataFromCommand | ConvertTo-Html | Set-Content "PathTo\File.html"

That gives you output like (as an HTML table):

Name    DataBaseSize    AvailableNewMailboxSpace    Difference
A - B       60.88 GB        4.88 GB                         56.00 GB
C - Dk      81.51 GB        6.78 GB                         74.73 GB

Or you can get a list:

$dataFromCommand | ConvertTo-Html -As List | Set-Content "PathTo\File.html"

which gives:

Name:                       A - B
DataBaseSize:               60.88 GB
AvailableNewMailboxSpace:   4.88 GB
Difference:                 56.00 GB
___________________________________
Name:                       C - Dk
DataBaseSize:               81.51 GB
AvailableNewMailboxSpace:   6.78 GB
Difference:                 74.73 GB

If you want this to be something you can set and forget,

make a script file with the following contents:

. 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'
Connect-ExchangeServer -auto
$properties = @(
    "name"
    @{Name="DataBaseSize";Expression={ "{0:N2} GB" -f (($_.DatabaseSize.ToBytes()) / 1gb) }}
    @{Name="AvailableNewMailboxSpace";Expression={ "{0:N2} GB" -f(($_.AvailableNewMailboxSpace.ToBytes()) / 1gb) }}
    @{Name="Difference";Expression={ "{0:N2} GB" -f (($_.DatabaseSize.ToBytes() - $_.AvailableNewMailboxSpace.ToBytes()) / 1gb) }}
)
# you might want to put this file on a file server somewhere
$pathToFile = "\\server\share\Some\Path\To\File.html"
$data = Get-mailboxdatabase -status | select $properties | sort-object name | ConvertTo-Html | Set-Content $pathToFile -Force

Then run the script from a scheduled task (if you are using PowerShell 2.0) For the scheduled task action, start a program, point the program at the Powershell executable (typically C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe) then set the "Add Arguments" field to: -NoLogo -NonInteractive R:\Full\Path\To\Script\script.ps1

Add whatever triggers you want, and boom, automatically maintained html file for your guys to monitor.

If you can use PowerShell 3.0 or above, you can do the following from any PowerShell prompt:

$trigger = New-JobTrigger -Daily -At 8:00AM
Register-ScheduledJob -Credential (Get-Credential) -FilePath "R:\Full\Path\To\script.ps1" -Name "Exchange MDB Size Stats" -Trigger $trigger
Joseph Alcorn
  • 2,322
  • 17
  • 23
  • Hi thanks for your help. To answer your first question of why I am trying to do this with a batch is because this is just one of the steps I am trying to accomplish. I want this powershell command to output to a .txt doc so I can then run a FOR loop against it and write the parameters to an html file which will then be blat'ed daily to my IT team to monitor the growth on the whitespace. – Eddie.Brown Nov 13 '13 at 16:51
  • BTW, as of PowerShell 2.0, there is a built in cmdlet called ConvertTo-Html that outputs a fully formed HTML doc. – Joseph Alcorn Nov 14 '13 at 01:26
  • Hi Joeseph, I literally put your batch suggestion into my own batch file and ran it to only receive the errors in my first post. – Eddie.Brown Nov 18 '13 at 23:31
  • Which one did you put in? I gave a couple of suggestions. It runs just fine for me against my exch 2010 instance – Joseph Alcorn Nov 19 '13 at 01:51
0

An alternative is to take Option 1 from @FinalizedFrustration's response and just have the batch file execute the script containing all of the commands like so:

@echo off
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noexit -command "Set-ExecutionPolicy Bypass Process -Force; & C:\<path-to-script>\MdbWhitespace.ps1"

Assuming MdbWhitespace.ps1 looks like:

. 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1';
Connect-ExchangeServer -auto;
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -EA SilentlyContinue
get-mailboxdatabase -status | select name, @{Name="DataBaseSize";Expression={ "{0:N2} GB" -f (($_.DatabaseSize.ToBytes()) / 1gb) }},@{Name="AvailableNewMailboxSpace";Expression={ "{0:N2} GB" -f (($_.AvailableNewMailboxSpace.ToBytes()) / 1gb) }},@{Name="Difference";Expression={ "{0:N2} GB" -f (($_.DatabaseSize.ToBytes() - $_.AvailableNewMailboxSpace.ToBytes()) / 1gb) }}

This is @FinalizedFrustrations original option #1 with the Add-PSSnappin inserted. I was assuming these were loaded into the PS environment (I don't work with Exchange so that may need to be modified).

His second option works better if you want to write multiple scripts that will get executed by this batch option.

beavel
  • 1,077
  • 1
  • 8
  • 16
  • Hi Beavel, when I run it as you suggest this I get errors, look at original post to see the errrors. – Eddie.Brown Nov 18 '13 at 23:22
  • @Eddie.Brown Please look at my above edits. The Add-PSSnappin should make sure Get-MailboxDatabases is available. I was thinking that was getting loaded by dot-sourcing RemoteExchange.ps1. – beavel Nov 19 '13 at 19:05