PST : How not to put a MailboxRequest in a queue - powershell

I need to export some PST. Problem is, when I use my foreach-object to export every PST one by one, they are all put in queue. But an other program is supposed to work using the PST at the same time.
dir | foreach-object {
$var = $_
New-MailboxExportRequest -Mailbox $var -Filepath "\\******\******tmp\pst\$var.pst"
}
I dont want my requests to be queued, I want them to be completed before starting an other one. For example, if the first request extracts pst1, i want it to be fully extracted before putting pst2in queue. Is there a way to do this ?

You can't change the Queue Behavior but you can force the exchage server to process only 1 pst each time
to achieve this, you need to edit the MSExchangeMailboxReplication.exe.config file located at:
<Exchange Installation Path>\Program Files\Microsoft\Exchange Server\V14\Bin
MaxActiveMovesPerSourceMDB - Default is 5 - Change it to 1
MaxActiveMovesPerTargetMDB - Default is 2 - Change it to 1
You might also need to change those setting as well:
MaxActiveMovesPerTargetServer
MaxActiveMovesPerSourceServer
of course if you want just to pause the foreach loop you can use the while statement (like Oggew suggested) to make sure the previous job completed before processing the next export

You could add something like this after you pass the New-MailboxExportRequest (inside the foreach-loop). If the export status equals "Queued" or "inprogress" the script will sleep for 15s and then check again. If the value changes status to completed it will pass in the next New-MailboxExportRequest.
while ((Get-MailboxExportRequest -Mailbox $var | Where {$_.Status -eq "Queued" -or $_.Status -eq "InProgress"}))
{
sleep 15
}

Related

Sent mail based on time that previous mail was sent

I have a script that checks if a site is online and sends a mail if it's down.
The script is configured with a scheduled task that runs every 30 minutes.
The problem is the following:
If the site is down during the weekend or evening (or a day when i'm not monitoring the mailbox), the mails keep being sent.
I was wondering, what method could I use to only send mails if the last time a mail was sent was 3 hours before?
Based on this way, i can send a mail only once every 3 hours.
I have researched the use of registry keys but was wondering if this would be the correct approach.
Rather than the registry, I'd use a simple configuraiton file stored in ProgramData (or AppData should you need a per user configuration)
This make the process of loading / saving parameters and adding new ones very easy.
Also, should you need to save logs and / or other data, you can just put them inside that same folder.
$ConfigFullPath = "$env:APPDATA\My Monitoring solution\config.json"
# This create the config file if none is present.
if (-not (Test-Path $ConfigFullPath)) {
New-Item -ItemType File -Path $ConfigFullPath -Value ([PSCustomObject]#{'LastEmailSent' = [datetime]::MinValue}| ConvertTo-Json) -Force
}
$ConfigFileParams = ConvertFrom-Json -InputObject (get-content "$env:APPDATA\My Monitoring solution\config.json" -raw)
$SendEmail = ([Datetime]::UtcNow - ([DateTime]$ConfigFileParams.LastEmailSent)).TotalHours -ge 3
if ($SendEmail) {
try {
# Send-MailMessage -ErrorAction Stop
# Once email is sent, we update the config
$ConfigFileParams.LastEmailSent = [DateTime]::UtcNow
$ConfigFileParams | ConvertTo-Json | Out-File $ConfigFullPath
}
Catch {
#Manage what to do in case of failure
}
}
That being said, you can definitely use the registry to do the same.
For convenience and ease of use though, I strongly suggest a simpler json file based approach.
I think the best option would be to write the starting hour in a file saved on the disk and everytime you run the script to test if
(currentHour-hourFirstSent)%3==0 && currentMinute<30
You put the name of the file yyyy-mm-dd and if that file exist you read the starting hour from it, if not you create it and save the starting hour in it.

Check servers reachable or not. Need to execute loop for 15 mins

Need some idea for this.
I have a scenario where i need to check server is reachable or not and if reachable then update value in excel as reachable=Y else default reachable=N. for which i am creating job and checking the state
Test-Connection -ComputerName $sHost -Count 1 -AsJob
Get-Job $JobID | Select State
it is working fine in a foreach loop.
now i need to keep this foreach loop inside some other loop and check maximum for 15 mins.
After 15 mins, which ever server having reachable=N, i have to ignore them and perform further action on the servers having reachable=Y
Need some idea on this how to build for this logic
The loop which ends after 15 minutes could look like this:
$startTime = Get-Date
while($startTime -gt (Get-Date).AddMinutes(-15)){
# Your Test-Connection loop
}
# Move on with your script...
To make your Test-Connection work with the while loop above, you cannot use the -AsJob parameter. Otherwise, there will be a massive amount of Jobs.
Edit based on comments
Change:
$RebootTime = Get-Date -Format "dd-MM-yyyy_hh:mm:ss"
at the top of your script to:
$startTime = Get-Date
$RebootTime = $startTime.ToString("dd-MM-yyyy_hh:mm:ss")

Stop a process running longer than an hour

I posted a question a couple ago, I needed a powershell script that would start a service if it was stopped, stop the process if running longer than an hour then start it again, and if running less than an hour do nothing. I was given a great script that really helped, but I'm trying to convert it to a "process". I have the following code (below) but am getting the following error
Error
"cmdlet Start-Process at command pipeline position 3
Supply values for the following parameters:
FilePath: "
Powershell
# for debugging
$PSDefaultParameterValues['*Process:Verbose'] = $true
$str = Get-Process -Name "Chrome"
if ($str.Status -eq 'stopped') {
$str | Start-Process
} elseif ($str.StartTime -lt (Get-Date).AddHours(-1)) {
$str | Stop-Process -PassThru | Start-Process
} else {
'Chrome is running and StartTime is within the past hour!'
}
# other logic goes here
Your $str is storing a list of all processes with the name "Chrome", so I imagine you want a single process. You'll need to specify an ID in Get-Process or use $str[0] to single out a specific process in the list.
When you store a single process in $str, if you try to print your $str.Status, you'll see that it would output nothing, because Status isn't a property of a process. A process is either running or it doesn't exist. That said, you may want to have your logic instead check if it can find the process and then start the process if it can't, in which case it needs the path to the executable to start the process. More info with examples can be found here: https://technet.microsoft.com/en-us/library/41a7e43c-9bb3-4dc2-8b0c-f6c32962e72c?f=255&MSPPError=-2147217396
If you're using Powershell ISE, try storing the process in a variable in the terminal, type the variable with a dot afterwards, and Intellisense (if it's on) should give a list of all its available properties.

Can I queue mailbox export to PST on Exchange Server 2010 SP3?

I am in a situation, when I would like to queue a few mailboxes to export (I don't want them to be processed at the same time) to PST files. I know, how to export them it with a command get-mailboxexportrequest, but when I do it, they almost instantly begin. Can I somehow queue another mailbox, so it would automatically start, when the previous one is completed?
I would do the following:
Build a powershell script which is checking if there is a running export happening (via Get-MailboxExportRequest) if that isn´t the case start to export x mailfiles you specify inside a CSV file
Use the Windows taskmanager on your Exchange Server to trigger that script and define a timeframe here how often and when your script should run
Once the powershell script runs, it should remove the exported mailfile from the CSV file and then quit
The next run from the powershell script via the taskmanager will then check if the current job is still ongoing, if it is, it should quit until its time to pick up the next entry from your list
Update:
As a starting point something like the following should be fine (untested but should give you a starting point):
# Get current Export Requests
$ExportStats = Get-MailboxExportRequest
#Check if there are completed questes
If ($ExportStats.Status -eq "Completed")
{
Write-Host "Export done"
Get-MailboxExportRequest -Status Completed -Name "$ObjectName-Export" | Remove-MailboxExportRequest -Confirm:$false
#Disable-Mailbox -identity "AD\$ObjectName"
# Create a new CSV file, which isn´t including the current export name we just marked as finish via above's section.
# CODE MISSING HERE!
# Now import our CSV list and proceed it
Import-CSV <Filepath of CSV file(\\server\folder\file.csv)> | ForEach-Object {
# Perform the export
New-MailboxExportRequest -Mailbox $_.MailboxAlias -FilePath $_.PSTpath
New-MailboxExportRequest -Mailbox $_.MailboxAlias -FilePath $_.ArchivePath
# Once done exit here, this will ensure we proceed only the first entry
Exit
}
}
elseif ($ExportStats.Status -eq "InProgress")
{
Write-Host "Export still ongoing"
}

copy / create multiple files

I need to first create and then copy some hundreds of folders & files via powershell (first create them on a local store and then copy them to a remote store).
However, when my foreach loop runs, every 40 or so write attempt fails due to "another process" which blocks the file/folder.
I currently fixed the issue using a simple sleep between every file creation (100ms). However, I wonder if there is no better way to do this? Especially when copying multiple files the sleep would depend on the network latency and dosn't seem to be a good solution to me.
Is there a way to "wait" till the write-operation of a file completed before starting another operation? Or to check if a file is still blocked by one process and wait till it's free again?
Have you tried running your code as a job? Example:
foreach ($file in $files) {
$job = Start-Job -ScriptBlock {
#operation here..
} | Wait-Job
#Log result of job using ex. $job and: '$job | Receive-Job' to get output
}
You could also extend it to create multiple jobs, and then use Get-Job | Wait-Job to wait for the all to finish before you proceed.