Items cannot be deleted from mailbox’s “deleted items” even using MFCMAPI.


Just recently I’ve got this weird issue.

Mailbox got stuck. I was able to remove emails from inbox folder and subfolders, even from the Recovery Items folder BUT… not from the deleted items folder.

The behaviour was weird – I was removing some emails and they were reappear after some time, same with MFCMAPI – was clicking hard delete and these bastards didn’t even move.

I was even not able to move the mailbox as it was telling me that mailbox exceeded the quota – I knew it – well, let me remove these emails then!!!

The reason for that appeared very trivial, I’ve been mentioning about this mechanism here:

Mailbox had litigation hold enabled and the “Purges” folder on the mailbox got filled up to 100GB. I thouhgt that these emails will be moved to archive but somehow these were still in the mailbox space causign the issue.

Removing the litigation hold allowed to finally delete the emails from deleted items.

Just as a reminder to check what is the size of the “Purges” folder run:

Get-MailboxFolderStatistics -Identity “<mailbox_name>” -FolderScope RecoverableItems -IncludeAnalysis | ft

[WTF?] VMware ESXi 6.5 – “Cannot complete login due to an incorrect user name or password”

Hi Chappies,

Just few momenst ago I had a really dodgy issue with loggin to newly installed ESXi6.5.

I deployed it few days ago, after instalation I logged in by copying password to the VMware console from KeePass application – logged in to that box, configured SSH connectivity and done some additinal configuration. After that connected via PuTTY as well.

Today my colleague just came from holidays and tried to log in – he got following error:


I thought that he we have some sort of different KeePass DB versions – but no.


I was not able to log in either! So I tried not to copy, but instead to type the password in the form field – same failure.

So, I went to the server room, and tried to log in directly to ESXi using KVM – and guess what? 🙂 All went well! So I came back to my desk, tried to log in by copy/paste credentials from KeePass – instant success!

The question that still remains in my head – and I hope VMware or someone from community might answer one day – is:


Anyone able to help in resolving the “(ES)X Files” riddle?

SQL long running jobs alert script in PowerShell

databaseHi folks!

Recently there was in a need of monitoring jobs on SQL – if they finish in timely manner. So I was looking for ready solution, found two: and however both are SQL jobs that monitor SQL jobs. I feel quite good in TSQL…


…however that solution didn’t suit me from few reasons:

  1. I wanted to do monitoring of SQL jobs as an independent from SQL jobs failure.
  2. I might need to modify add something in the future and it would be easier for me in PowerShell
  3. Above solutions were giving alerts when a job run time was above average – not over certain time – an I needed that. Didn’t know how to do it in SQL.

So the decision was made:


To make it running in your environment just modify these lines:

## 10th-12th LINE
$fromemail = ''
$mailserver = ''
$toemail = ''
## 21st LINE
## 71st LINE
if ($Date_Diff.TotalMinutes -gt 5){

So in this example a script will send an email in HTLM:

If a job runs over 5 minutes.

So there you go 🙂 it is easy, no parameters and really dirty. I like it 🙂

Script can be found on TechNet and GitHub.

HP MSA – PowerShell script to check if disk drives firmware revision is up to date.

Recently I came across updating firmware on some HP MSA appliances.

As there were many different disk drives models on those, I started to wonder – how would I know if any new firmware has been released?

I didn’t want to search firmware for 10 different disk drives models every quarter neither. Firstly because I would forget, secondly – time consuming.

It was no brainer that I needed some automation for that stuff.

I found a HP website providing disk drives firmwares:

Unfortunately I was not able to find any of these for controller firmwares or enclosures.

Fortunately for controllers and enclosures checkout is easy, also usually we get information in controller firmware documentation which firmware revision is recommended for enclosure.

Script need to have current MSA firmware information in a JSON file – as for now this process is not automated and information need to be put manually in the JSON file.

What script does is it is going though mentioned website creating hash array of objects basing on very hideous HTML parsing (yup, I know it is ugly AF but well… works ^^).

After it got all that shit from the website, it runs array one by one checking looking for particular object by disk model, and comparing it’s current firmware revision from JSON to what it found on the website.

And here is the thing, there are 3 statuses:

Green – disk has the newest firmware

Light Green – disk most probably has the newest firmware.

Red – disk has an old firmware

You might ask – why we need Light Green. Well, sometimes one disk drive model is visible twice as different model, like below:



So these two are the same model, but have different firmware.

If script finds such situation, it checks if your firmware revision is among these found on the website – it also lists what firmware revisions have been found for that particular drive model. If your firmware revision is there – drive is reported as light green.

Output should look like:


As you probably noticed for controllers there is just list to verify firmware version – I didn’t find any good source to script can run trough it checking if it is up to date, so as a workaround there is a fixed link in JSON file – it is always better just to click it and check current version than to search every quesrter for the correct link.

Script has 4 simple switches:

-File – switch parameter, if ran with that it will generate HTML file

-FilePath – default path is “.\”, so if you want to put HTML file somewhere else – this is the right place

-Email – switch parameter, if ran with that it will generate an email.

-Verbose – you got additional information about what actions have been done

Hope it will be helpful for some of you guys.

Script can be found on TechNet and GitHub.

PowerShell script to check permissions on mailbox folders (also recursively).

Hey there!

Some time ago I posted script that is checking general permissions of a mailbox like “FullAccess”, “ReadOnly” etc.:

Here is another one that is checking permissions on particular folders 🙂

Worth mentioning is that script is also checking groups recursively, and has – let me call it – anti-loop protection :] so if someone creates “Group_A” and “Group_B” and put A in B and B in A the script will notice that particular group has been already reported in that particular cycle, and won’t go deeper.

Parameters and examples:

MailboxFolderPermissions.ps1 – Mailbox folder permissions report generation script.

Generates a report of permissions that have been set on a folder

Single mailbox reports are output to the console, while all other
reports are output to a CSV file.

Generates a report for all mailboxes in the organization.

Generates a report for all mailboxes on the specified server.

.PARAMETER database
Generates a report for all mailboxes on the specified database.

Generates a report for mailbox names listed in the specified text file.

.PARAMETER mailbox
Generates a report only for the specified mailbox.

.PARAMETER filename
(Optional) Specifies the CSV file name to be used for the report.
If no file name specificed then a unique file name is generated by the script.

.\MailboxFolderPermissions.ps1 -database HO-MB-01
Returns a report with the mailbox statistics for all mailbox users in
database HO-MB-01

.\MailboxFolderPermissions.ps1 -file .\users.txt
Returns a report with the mailbox statistics for all mailbox users in
the file users.txt. Text file should contain names in a format that
will work for Get-Mailbox, such as the display name, alias, or primary
SMTP address.

.\MailboxFolderPermissions.ps1 -server ex2010-mb1
Generates a report with the mailbox statisitcs for all mailbox users
on ex2010-mb1

.\MailboxFolderPermissions.ps1 -server ex2010-mb1 -filename ex2010-mb1.csv
Generates a report with the mailbox statisitcs for all mailbox users
on ex2010-mb1, and uses the custom file name of ex2010-mb1.csv

Script can be downloaded from Technet and GitHub.

Remove cancelled Outlook meetings using PowerShell and EWS.



Recently there was a business demand for removal of meetings that were canceled in our resource mailboxes. Thought it was some sort of  a bug but then saw that problem was “AutomateProcessing” attribute on these was set to “AutoUpdate” not “AutoAccept” (This can be checked using Get-CalendarProcessing cmdlet).


So when someone is scheduling a meeting form his own mailbox and is picking up room – creates a meeting, and later changes his mind and removes it, it still is hanging there visible as “Canceled: Subject of the meeting“. And each time (because of that “AutoUpdate”) someone manually needs to go there and remove it.


After reading a bit about that topic, I realized that PowerShell script I was about to write needs to use EWS and impersonation in Exchange.

There are few things you need before running the script:

  • AD account used by the script
  • Security Group that will contain people who will have impersonation rights (admns/service accounts)
  • Distribution List that will contain room mailboxes – managed by admins/service accounts from Security Group
  • Management Scope in Exchange – narrowing scope for members of the Distribution List
  • Management Role Assigment – glue all that crap together – permission Security Group to Distribution List with “Application Impersonation” rights.

In commands it can look like:

1. Creating Distibution Group

New-DistributionGroup -Name ‘RoomImpersonationGroup‘ -Type ‘Distribution’ –OrganizationalUnit ‘ Lists’ -SamAccountName ‘RoomImpersonationGroup’ -Alias ‘RoomImpersonationGroup’ –managedBy ‘PawelJarosz’

2. Creation of Exchange Management Scope:

$Grupa = Get-DistributionGroup -Identity “RoomImpersonationGroup”
New-ManagementScope “Room Mailboxes Impersonation” -RecipientRestrictionFilter “MemberOfGroup -eq ‘$($Grupa.DistinguishedName)'”

3. Creation of security group “ExchangeRoomImpersonation” in Active Directory

NEW-ADGroup –name “ExchangeRoomImpersonation” –groupscope Universal –path “OU=Offices,DC=Contoso,DC=local” -GroupCategory Security

4. Creation of new Exchange Assigment Role:

New-ManagementRoleAssignment -Name “Room Mailboxes Impersonation Assigment” -Role “ApplicationImpersonation” -CustomRecipientWriteScope “RoomImpersonationGroup” -SecurityGroup “ExchangeRoomImpersonation”


If you have all of that or you do not need to configure it as there are some service accounts you will use that are permissioned to impersonate globally – omit all these steps.

Some details about the script:

DeleteCanceledMeetings.ps1 - Cancelled meetings removal script.

.PARAMETER SearchStartDay
(OPTIONAL) Specifies START date from which sript should start searching of 
If not specified the today's date is used.

(MANDATORY) Specifies END date till which sript should start searching of 

(MANDATORY) Specifies mailboxes from which cancelled meetings should be removed.
As this is an array it accepts many mailboxes given after coma.

(OPTIONAL) Triggers HardDelete action on cancelled meetings if equal "True". 
Without it it generates a on screen report.

.\Get-MailboxPermissions.ps1 -SearchStartDay 10 -SearchEndDay 30 -Room Room1,Room2
Starts searching of meetings 10 days back and 30 days in front 
for 3 rooms Room1,Room2.
Returns a on screen report.

.\Get-MailboxPermissions.ps1 -SearchEndDay 90 -Room Room1,Room2,Room3 `
 -HardDetele True
Starts searching of meetings starting from current day and 90 days in front 
for 3 rooms Room1,Room2,Room3 and hard deletes them.
Reruns a CSV report and a log file.

You need to modify these lines in order to get logging working:


And you are ready to go! 🙂

Please remember that when runnig the script:


Script can be found on my Technet and GitHub

Have fun with IT!

VENI -Event | { $_.speech -VIDI $true; $global:State =+ VICI}

PowerShell Conference EU 2016


Being at the PowerShell conference in Hannover this Spring was a refreshing experience.

Met a lot of people that few days back I could only dream to meet. Starting from left picture with Bartek Bielawski, Bruce Payette and Jeffrey Snover, but I guess no one from them requires a real introduction 🙂

Talking about how great it was would take too much time (briefly: lots of inspirational speeches, great party in zoo with amazing food! :D, perfect opportunity to connect) so just encouraging those from you who are still hesitating to join PSConf next year! It is worth not only because of the technical factor but maybe even more because of people who are really open, friendly and full of incredible positive energy!


>> <<



CMTrace log viewer

CMTrace is a great log viewer:

Nice to have as it is showing errors and warnings in different colours and gives you possiblity to look at the log in the real time as it is still building:

Toolkit default installation path is “C:\Program Files (x86)\ConfigMgr 2012 Toolkit R2”.



A few PowerShell tips – Part 2 – Useful commands / switches.

Few days ago I wrote similar article:

Part 1 :


Here is another portion of PowerShell features I find worth remembering, and I tend to forget about. Actually this is the reason why all these articles are here ^^


Show-Command – GUI to build PowerShell commands


Show-Command: That feature came out in PowerShell 3.0. Gives great ability to create commands in situation when you are not feeling so well with the shell yet, or if you simply would like to check all the attributes of a certain command:


We can see that there is possibility to set even things like pipeline variable (that particular appeared in PowerShell 4.0 – here is a great article about it: and many others through the GUI.


How to check PowerShell version installed


By the way, to check PowerShell version commands “host” or “$PSVersionTable” can be used:



Simply “one-liners” simpler with version 3.0


Starting from version 3.0 there there is a possibility to use simplified syntax (but only for simple commands like single property listing etc.), for example in PowerShell 2.0 simply Get-Mailbox would look like:

Get-Mailbox | ? {$ -match “test”}

And other, shorter, way we can do the same in PowerShell 3.0:

Get-Mailbox | ? name -match test


So there is no need for “$_.”, braces and quotes 🙂


Be lazy and set default parameters for cmdlets 🙂


Another worth mentioning thing is $PSDefaultParameterValues. Variable is set per session, and can be overwritten. Example usage:

$PSDefaultParameterValues = @{“get-wmiobject:class”=”win32_bios”}

After that when running gwmi cmdlet we wil by default will get win32_bios class:



 -expandproperty – but why?




If you haven’t used that yet, you might be asking, why it is a cool thing to use. Here is a good example. You plan to use Get-WmiObject cmdlet that is not accepting pipelining – why? Because yo udo not want to use Get-CimInstance that accepts pipelining and does same…  🙂 Anyway after trying to read Win32_BIOS class you might get:


The exit from that situation is to get computer name, and puke it out from cmdlet as string – not an object:




Label and expression – custom naming properties


This one is more useful you might expect 🙂 Great example can be found here:

where Jeff and Jason are explaining how to understand usage of pipe.

Here is also great article about it:

Ed tells there that we can run a pipeline using property “by value” and “by name”, but there is a problem while we have a different name. And here somes the help! Example:

Let’s say we got one workstation and we would like to read status of particular service form it. If we run it Get-ADComputer and we run a simply pipe on Get-Service – we will ger an error:


BUT WHY!?!?!?!!?


Hey sure! Telling you now. So what we need to check is: Do we have something, which can let us to connect these two cmdlets to each other?

Firstly let’s check Get-ADComputer:


Property is with the computer name is “Name”. Now we need to get state of one service on that workstation, we check if Get-Service if there is a change to get hookup:


So what we need to do here is…:


…and TAAADAAAAM!! All we needed to do is to change the property name.

“n” is alias “name”, you can also use “l” for label in exchagne. “e” is for expression. So that part of a command might look like:

select @{name=’ComputerName’;expression={$}}


select @{label=’ComputerName’;expression={$}}


-PassThru the command


You want to run a command and see a right away output of what you did? No problem, just use “-PassThru” switch!