Powershell Exchange - help using invoke-command

I am trying make a remote session to Exchange server and then archiving to PST. I am having some trouble figuring how to pass variables to the invoke-command line.


function Show-Menu
{
    param ([string]$Title = 'Menu')
    cls
    Write-Host "================ $Title ================"

    Write-Host ""     
    Write-Host "1: Archive .PST"
    Write-Host "Q: Quit."
}


$ExchangeServer = "server"
$Credential = Get-Credential  -Message "Enter Domain\username"
$SessionParams =
@{
   ConfigurationName = 'Microsoft.Exchange'
   ConnectionURI     = "http://$ExchangeServer/powershell/"
   Authentication    = 'Kerberos'
   Credential = $Credential
}

$Session = New-PSSession @SessionParams


do
{
     Show-Menu
     $input = Read-Host "Chose one"
     switch ($input)
     {
        '1' {
                cls

                $PstPath = "\\server\c$\temp"

                $user = Read-Host "Enter mailbox"
                $date = Read-Host "Enter month/year (m-yyyy)"
                $arrDate = $date.Split('-')
                $firstDayOfMonth = Get-Date -Date "$($arrDate[1])-$($arrDate[0])-1 00:00:00"
                $lastDayOfMonth = $firstDayOfMonth.AddMonths(1).AddDays(-1)


                New-Item $PstPath\$user -type directory -Force

                Invoke-command -ScriptBlock { New-MailboxExportRequest -ContentFilter {(Received -ge $firstDayOfMonth) -and (Received -lt $lastDayOfMonth)} -Mailbox $user -FilePath $PstPath\$user\$date.pst} -Session $Session
                }

        'q' {
                Remove-PSSession $exchange10
                return
            }
     }
     pause
     
}
until ($input -eq 'q')
Mike NielsenAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jack jonesCommented:
Enable PSRemoting Transport Exception
0
Mike NielsenAuthor Commented:
Hi Nitz, I am able to remote, but the variable in the scriptBlock is all empty/null, because i don't know how to pass it.
0
sirbountyCommented:
Are you getting any specific error?  What sort of environment is available on the remote machine?  I.e. does it have the exchange modules loaded?
0
Redefine Your Security with AI & Machine Learning

The implications of AI and machine learning in cyber security are massive and constantly growing, creating both efficiencies and new challenges across the board. Check out our on-demand webinar to learn more about how AI can help your organization!

Mike NielsenAuthor Commented:
The remote machine does not have exchange modules installed. I want to run the command on the Exchange server (exchange 2010) if possible. Also the remote user running the script, does not have admin rights, so I want to run the command using remote session, with the entered credentials with full privileges.

I am getting this error:
Cannot validate argument on parameter 'Mailbox'. The argument is null. Supply a non-null argument and try the command again.
    + CategoryInfo          : InvalidData: (:) [New-MailboxExportRequest], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,New-MailboxExportRequest
    + PSComputerName        : server
0
oBdACommented:
A script block knows nothing about the rest of the script. You have to pass it the arguments you want to use, similar to a function.
Difference to a function: the argument list for script blocks is always positional, never "by name" (I've used the same name for the arguments as for the main script, but that isn't a requirement).
Function Show-Menu {
	Param ([string]$Title = 'Menu')
	cls
	Write-Host "================ $Title ================"
	
	Write-Host ""     
	Write-Host "1: Archive .PST"
	Write-Host "Q: Quit."
}

$ExchangeServer = "server"
$Credential = Get-Credential -Message "Enter Domain\username"
$SessionParams = @{
	ConfigurationName	= 'Microsoft.Exchange'
	ConnectionURI		= "http://$ExchangeServer/powershell/"
	Authentication		= 'Kerberos'
	Credential			= $Credential
}
$Session = New-PSSession @SessionParams

Do {
	Show-Menu
	$Input = Read-Host "Choose one"
	Switch ($Input) {
		'1' {
			cls
			$PstPath = "\\server\c$\temp"
			$Mailbox = Read-Host "Enter mailbox"
			New-Item $PstPath\$Mailbox -Type Directory -Force
			$ArchiveDate = Read-Host "Enter month/year (m-yyyy)"
			Invoke-Command -Session $Session -ArgumentList $PstPath, $Mailbox, $ArchiveDate -ScriptBlock {
				Param($PstPath, $Mailbox, $ArchiveDate)
				$Month, $Year = $ArchiveDate.Split('-')
				$FirstDayOfMonth = Get-Date -Date "$($Year)-$($Month)-1 00:00:00"
				$LastDayOfMonth = $FirstDayOfMonth.AddMonths(1).AddDays(-1)
				New-MailboxExportRequest -ContentFilter {(Received -ge $FirstDayOfMonth) -and (Received -le $LastDayOfMonth)} -Mailbox $Mailbox -FilePath $PstPath\$Mailbox\$ArchiveDate.pst
			}
		}
		'q' {
			Remove-PSSession $Session
		}
		default {
			Write-Warning "Unknown choice '$_' - try again."
		}
	}
	pause
} Until ($Input -eq 'q')

Open in new window


Note: when posting code, please put it into [code][]/code] tags (see toolbar above the input field).
0
Mike NielsenAuthor Commented:
Oh ye btw.. If I run the Invoke-command without variables, (so i enter mailboxname, date and path myself).. Then it works fine.
0
Mike NielsenAuthor Commented:
@oBdA Oh thank you very much! Just what I was looking for :).. I also made it work somehow using "Import-PSSession" without the invoke-command, but then it seems like it creates 2 PSSession. I guess the Invoke-Command would be the correct way to go. Thanks again. I will test it later
0
Mike NielsenAuthor Commented:
@oBdA

It seems to work. The PST is archived, but I still get an error message. Seems to be something wrong with the date?  

The term 'Get-Date' 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.

    + CategoryInfo          : ObjectNotFound: (Get-Date:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
    + PSComputerName        : server
 
You cannot call a method on a null-valued expression.
    + CategoryInfo          : InvalidOperation: (AddMonths:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
    + PSComputerName        : server

I am doing the same code as you posted:

		'1' {
			cls
			$PstPath = "\\server\c$\temp"
			$Mailbox = Read-Host "Enter mailbox"
			New-Item $PstPath\$Mailbox -Type Directory -Force
			$ArchiveDate = Read-Host "Enter month/year (m-yyyy)"
			Invoke-Command -Session $Session -ArgumentList $PstPath, $Mailbox, $ArchiveDate -ScriptBlock {
				Param($PstPath, $Mailbox, $ArchiveDate)
				$Month, $Year = $ArchiveDate.Split('-')
				$FirstDayOfMonth = Get-Date -Date "$($Year)-$($Month)-1 00:00:00"
				$LastDayOfMonth = $FirstDayOfMonth.AddMonths(1).AddDays(-1)
				New-MailboxExportRequest -ContentFilter {(Received -ge $FirstDayOfMonth) -and (Received -le $LastDayOfMonth)} -Mailbox $Mailbox -FilePath $PstPath\$Mailbox\$ArchiveDate.pst
			}

Open in new window

0
oBdACommented:
That's rather strange, should not happen, and has nothing to do with the script itself. Get-Date is part of the Microsoft.PowerShell.Utility module and should be loaded automatically.
You can try to explicitly load the module at the beginning of the ScriptBlock:
...
Param($PstPath, $Mailbox, $ArchiveDate)
Import-Module Microsoft.PowerShell.Utility
...

Open in new window

Or you can work your way around it by calculating the date locally and then passing it on to the remote machine:
Function Show-Menu {
	Param ([string]$Title = 'Menu')
	cls
	Write-Host "================ $Title ================"
	
	Write-Host ""     
	Write-Host "1: Archive .PST"
	Write-Host "Q: Quit."
}

$ExchangeServer = "server"
$Credential = Get-Credential -Message "Enter Domain\username"
$SessionParams = @{
	ConfigurationName	= 'Microsoft.Exchange'
	ConnectionURI		= "http://$ExchangeServer/powershell/"
	Authentication		= 'Kerberos'
	Credential			= $Credential
}
$Session = New-PSSession @SessionParams

Do {
	Show-Menu
	$Input = Read-Host "Choose one"
	Switch ($Input) {
		'1' {
			cls
			$PstPath = "\\server\c$\temp"
			$Mailbox = Read-Host "Enter mailbox"
			New-Item $PstPath\$Mailbox -Type Directory -Force
			$ArchiveDate = Read-Host "Enter month/year (m-yyyy)"
			$Month, $Year = $ArchiveDate.Split('-')
			$FirstDayOfMonth = Get-Date -Date "$($Year)-$($Month)-1 00:00:00"
			Invoke-Command -Session $Session -ArgumentList $PstPath, $Mailbox, $ArchiveDate, $FirstDayOfMonth -ScriptBlock {
				Param($PstPath, $Mailbox, $ArchiveDate, $FirstDayOfMonth)
				$LastDayOfMonth = $FirstDayOfMonth.AddMonths(1).AddDays(-1)
				New-MailboxExportRequest -ContentFilter {(Received -ge $FirstDayOfMonth) -and (Received -le $LastDayOfMonth)} -Mailbox $Mailbox -FilePath $PstPath\$Mailbox\$ArchiveDate.pst
			}
		}
		'q' {
			Remove-PSSession $Session
		}
		default {
			Write-Warning "Unknown choice '$_' - try again."
		}
	}
	pause
} Until ($Input -eq 'q')

Open in new window


Actually, you seem not to be the only one with that issue:

intermittent : The term 'get-date' is not recognized as the name of a cmdlet, function, script file, or operable program.
https://social.technet.microsoft.com/Forums/ie/en-US/edc4ae2d-b804-4361-94de-7482533a8084/intermittent-the-term-getdate-is-not-recognized-as-the-name-of-a-cmdlet-function-script-file?forum=winserverpowershell

Powershell commands not working in Build Events in Visual Studio
http://stackoverflow.com/questions/28810631/powershell-commands-not-working-in-build-events-in-visual-studio
0
Mike NielsenAuthor Commented:
Strange. Now I get this error when going date calculation before scriptblock. So I should convert it to a string or something?:

The provided ContentFilter value is invalid. ContentFilter is invalid. Unable to cast object of type 'System.Management.Automation.PSObject' to type 'System.String'. -->
 Unable to cast object of type 'System.Management.Automation.PSObject' to type 'System.String'.
    + CategoryInfo          : InvalidArgument: ((Received -ge $...LastDayOfMonth):String) [], ContentFilterInvalidPermanentException
    + FullyQualifiedErrorId : FBF5F982
    + PSComputerName        : server

And when doing import-module I get this error:
The term 'Import-Module' 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.
    + CategoryInfo          : ObjectNotFound: (Import-Module:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
    + PSComputerName        : server
 
The term 'Get-Date' 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.
    + CategoryInfo          : ObjectNotFound: (Get-Date:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
    + PSComputerName        : server
 
You cannot call a method on a null-valued expression.
    + CategoryInfo          : InvalidOperation: (AddMonths:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
    + PSComputerName        : server
0
oBdACommented:
Sorry, can't test this at the moment.
Try it like this:
Function Show-Menu {
	Param ([string]$Title = 'Menu')
	cls
	Write-Host "================ $Title ================"
	
	Write-Host ""     
	Write-Host "1: Archive .PST"
	Write-Host "Q: Quit."
}

$ExchangeServer = "server"
$Credential = Get-Credential -Message "Enter Domain\username"
$SessionParams = @{
	ConfigurationName	= 'Microsoft.Exchange'
	ConnectionURI		= "http://$ExchangeServer/powershell/"
	Authentication		= 'Kerberos'
	Credential			= $Credential
}
$Session = New-PSSession @SessionParams

Do {
	Show-Menu
	$Input = Read-Host "Choose one"
	Switch ($Input) {
		'1' {
			cls
			$PstPath = "\\server\c$\temp"
			$Mailbox = Read-Host "Enter mailbox"
			New-Item $PstPath\$Mailbox -Type Directory -Force
			$ArchiveDate = Read-Host "Enter month/year (m-yyyy)"
			$Month, $Year = $ArchiveDate.Split('-')
			$FirstDayOfMonth = Get-Date -Date "$($Year)-$($Month)-1 00:00:00"
			$LastDayOfMonth = $FirstDayOfMonth.AddMonths(1).AddDays(-1)
			Invoke-Command -Session $Session -ArgumentList $PstPath, $Mailbox, $ArchiveDate, $FirstDayOfMonth, $LastDayOfMonth -ScriptBlock {
				Param($PstPath, $Mailbox, $ArchiveDate, $FirstDayOfMonth, $LastDayOfMonth)
				New-MailboxExportRequest -ContentFilter {(Received -ge $FirstDayOfMonth) -and (Received -le $LastDayOfMonth)} -Mailbox $Mailbox -FilePath $PstPath\$Mailbox\$ArchiveDate.pst
			}
		}
		'q' {
			Remove-PSSession $Session
		}
		default {
			Write-Warning "Unknown choice '$_' - try again."
		}
	}
	pause
} Until ($Input -eq 'q')

Open in new window


And Import-Module is part of Microsoft.PowerShell.Core and really should be there. What's the Windows and Powershell  version ($PSVersionTable) on the Exchange server?
0
Mike NielsenAuthor Commented:
Getting this :/

The provided ContentFilter value is invalid. ContentFilter is invalid. Unable to cast object of type 'System.Management.Automation.PSObject' to type 'System.String'. -->
 Unable to cast object of type 'System.Management.Automation.PSObject' to type 'System.String'.
    + CategoryInfo          : InvalidArgument: ((Received -ge $...LastDayOfMonth):String) [], ContentFilterInvalidPermanentException
    + FullyQualifiedErrorId : FBF5F982
    + PSComputerName        : server

Not sure if I should check on the EMS or powershell, so i did both (running Exchange 2010 on Windows Server 2012):

Exchange EMS
Name                           Value
----                           -----
CLRVersion                     2.0.50727.6421
BuildVersion                   6.1.7600.16385
PSVersion                      2.0
WSManStackVersion              2.0
PSCompatibleVersions           {1.0, 2.0}
SerializationVersion           1.1.0.1
PSRemotingProtocolVersion      2.1

Windows Powershell at server:
Name                           Value
----                           -----
PSVersion                      3.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.18449
BuildVersion                   6.2.9200.17065
PSCompatibleVersions           {1.0, 2.0, 3.0}
PSRemotingProtocolVersion      2.2
0
oBdACommented:
This should work now as far as processing the date on the local machine is concerned:
Function Show-Menu {
	Param ([string]$Title = 'Menu')
	cls
	Write-Host "================ $Title ================"
	
	Write-Host ""     
	Write-Host "1: Archive .PST"
	Write-Host "Q: Quit."
}

$ExchangeServer = "server"
$Credential = Get-Credential -Message "Enter Domain\username"
$SessionParams = @{
	ConfigurationName	= 'Microsoft.Exchange'
	ConnectionURI		= "http://$ExchangeServer/powershell/"
	Authentication		= 'Kerberos'
	Credential			= $Credential
}
$Session = New-PSSession @SessionParams

Do {
	Show-Menu
	$Input = Read-Host "Choose one"
	Switch ($Input) {
		'1' {
			cls
			$PstPath = "\\server\c$\temp"
			$Mailbox = Read-Host "Enter mailbox"
			New-Item $PstPath\$Mailbox -Type Directory -Force
			$ArchiveDate = Read-Host "Enter month/year (m-yyyy)"
			$Month, $Year = $ArchiveDate.Split('-')
			$FirstDayOfMonth = Get-Date -Date "$($Year)-$($Month)-1 00:00:00"
			$LastDayOfMonth = $FirstDayOfMonth.AddMonths(1).AddDays(-1)
			Invoke-Command -Session $Session -ArgumentList $PstPath, $Mailbox, $ArchiveDate, $FirstDayOfMonth.ToShortDateString(), $LastDayOfMonth.ToShortDateString() -ScriptBlock {
				Param($PstPath, $Mailbox, $ArchiveDate, $FirstDayOfMonth, $LastDayOfMonth)
				New-MailboxExportRequest -ContentFilter {(Received -ge $FirstDayOfMonth) -and (Received -le $LastDayOfMonth)} -Mailbox $Mailbox -FilePath $PstPath\$Mailbox\$ArchiveDate.pst
			}
		}
		'q' {
			Remove-PSSession $Session
		}
		default {
			Write-Warning "Unknown choice '$_' - try again."
		}
	}
	pause
} Until ($Input -eq 'q')

Open in new window


When in the EMS directly, can you successfully run the "Get-Date" command?
0
Mike NielsenAuthor Commented:
"Get-Date" command works fine directly from the EMS. Not sure if it got something to do with language problems. Now I am getting this error when doing 3-2017 (31-03-2017 is danish timeformat):

The provided ContentFilter value is invalid. ContentFilter is invalid. The value "31-03-2017" could not be converted to type System.DateTime. --> The value "31-03-2017" could not be converted to type System.DateTime.
    + CategoryInfo          : InvalidArgument: ((Received -ge $...LastDayOfMonth):String) [], ContentFilterInvalidPermanentException
    + FullyQualifiedErrorId : D23A681B
    + PSComputerName        : server
0
oBdACommented:
The DateTime conversion seems to expect a yyyy-MM-dd format when a string with '-' as field separator is encountered.
In line 34, replace the date arguments in -ArgumentList $FirstDayOfMonth.ToShortDateString(), $LastDayOfMonth.ToShortDateString() with this:
$FirstDayOfMonth.ToString('yyyy-MM-dd'), $FirstDayOfMonth.ToString('yyyy-MM-dd')

Open in new window

If this doesn't work, try the American format:
$FirstDayOfMonth.ToString("MM'/'dd'/'yyyy"), $FirstDayOfMonth.ToString("MM'/'dd'/'yyyy")

Open in new window

1

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Mike NielsenAuthor Commented:
Working now! Thank you for all the help - really appreciate it.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.