PowerShell: List all installed applications

Note: This PowerShell command only works on earlier versions (5 or below). This does NOT work in latest PowerShell versions.

Get-WmiObject -Class Win32_Product | select Name,Vendor,version | Sort-Object -Property Name


Exchange/Outlook: Emails sent as shared mailbox stored in Sent Items folder in my mailbox, Why?

Here is the setup. I have configured my mailbox in Outlook. I have added second mailbox to the same Outlook mail profile (usually a shared mailbox). I have send-as permissions on that shared mailbox. I sent email as the shared mailbox, those sent emails are freaking stored in Sent Items in MY MAILBOX. Why?

Because somebody in Microsoft thought that’s a GREAT idea. Or they think they can piss off lots of people. Exchange Devs!! You achieved your goal!

Microsoft explained about the Registry Key DelegateSentItemsStyle (at HERE) that you can make the Outlook to store the emails “send-as” shared mailbox to be stored in Shared Mailbox. Note to Microsoft: That must be the default setting.

If DelegateSentItemsStyle is 0 (default value), emails that sent-as shared mailbox WILL be stored in your mailbox. Value 1 is what we want that send-as emails store in “Sent Items” folder in Shared mailbox.

FIX: follow the instruction below to change the registry key

  1. Exit Outlook.
  2. Start Registry Editor. Press Windows Key+R to open a Run dialog box. Type regedit.exe and then press OK.
  3. Locate and then select the following registry key: HKEY_CURRENT_USER\Software\Microsoft\Office\<x.0>\Outlook\Preferences
  4. Select the DelegateSentItemsStyle value.
  5. On the Edit menu, select Modify.
  6. Type 1, and then select OK.
  7. Exit Registry Editor.
  8. Start Outlook.

Note on step 3: In this key path, the placeholder <x.0> represents 16.0 for Outlook 2016, Outlook for Office 365 and Outlook 2019.

Exchange Online: Remove-Mailbox: The following error occurred during validation in agent ‘Windows LiveId Agent’: ‘Unable to perform the save operation. ‘SharedMailboxName’ is not within a valid server write scope.’

All you want to do is delete a Shared Mailbox in Exchange Online. But it is stupidly stubborn. It doesn’t want to delete. All you get is

Remove-Mailbox: The following error occurred during validation in agent ‘Windows LiveId Agent’: ‘Unable to perform the save operation. ‘SharedMailboxName’ is not within a valid server write scope.’

SOLUTION: Delete the related Azure AD user account. In the following example, I removed related MSOL user account, that also removes the shared mailbox.

Get-MsolUser -UserPrincipalName stubbornsharedmailbox@company.com | Remove-MsolUser -Force

You can also use AzureAD PowerShell cmdlet or Azure AD console in Azure to remove the user account.

Exchange Online: Cannot replace PrimarySMTPAddress of a mailbox

You try to replace the Primary email address (PrimarySMTPAddress) OR a secondary email address/Alias on a mailbox in Exchange Admin Center. After replacing the email address, you save the changes. Reopen the mailbox properties, you see the FREAKING primary email address still FREAKING there.

I am sure you tried to replace the email address using

Set-Mailbox -Identity MailboxName -PrimarySMTPAddress Name@newdomainname.com

Command runs and no errors seen. BUT the PrimarySMTPAddress is still FREAKING there. What the HELL is going on here?

Here is the solution: Replace WindowsEmailAddress and MicrosoftOnlineServicesID with the new email address first on Mailbox properties, then modify the PrimarySMTPAddress. Here are the sample PowerShell cmdlets:

Set-Mailbox -Identity MailboxName -MicrosoftOnlineServicesID name@newdomainname.com
Set-Mailbox -Identity MailboxName -WindowsEmailAddress name@newdomainname.com
Set-Mailbox -Identity MailboxName -PrimarySMTPAddress name@newdomainname.com

If you are changing the secondary email address/alias, use this cmdlet:

Set-Mailbox -Identity MailboxName -EmailAddresses @{Remove="oldemail@domain.com"}
Set-Mailbox -Identity MailboxName -emailAddresses @{Add="newemail@domain.com"}

Hope that was as easy as this solution. Enjoy!

Is ADMT Driving you Crazy? This operation requires that auditing be enabled for Success and Failure auditing of account management operations.

According to ADMT 3.2: Interforest Migration – Part 3 – TechNet Articles – United States (English) – TechNet Wiki (microsoft.com) you enable Success and Failure for the policy “Audit account management” in Default Domain Controllers Policy.

Now you are trying to migrate users or groups or computers using ADMT console. You get this freaking error:

011-10-25 14:03:23 ERR2:7430 SID History for <account name> cannot be updated because auditing is not enabled on <target domain>.   rc=8536.\n  This operation requires that auditing be enabled for Success and Failure auditing of account management operations.

2011-10-25 14:03:23 WRN1:7392 SIDHistory could not be updated due to a configuration or permissions problem.  The Active Directory Migration Tool will not attempt to migrate the remaining objects.

2011-10-25 14:03:23 Operation Aborted.

You might be wondering you already enabled auditing in the GPO. Why the HELL are you getting this error?

I believe Microsoft meant to enable auditing in Default Domain Controllers Policy under Computer Configuration >>> Polices >>> Windows Settings >>> Security Settings >>> Advanced Audit Policy Configuration >>> Account Management. and Enable all Auditing policies.

Another Advise is to use SAME ACCOUNT for Source and Target domains during ADMT migration wizard. After you created TRUST between domains, make your (or service) account as administrator to the source domain like this:

  • add your (or a service account) to a LOCAL security group (I named it ADMT-Admins) in source domain
  • Add the Local Security Group (ADMT-Admins) to Administrators built-in group.

Exchange: Prevent sending Out of Office replies from Group/DL Members back to the Senders

I have been asked to prevent sending Out of Office replies from a DL members to the senders. The context of the request is the DL is published externally to the customers. If the customers send email to get help, we don’t want to send Out of Messages back to the customers.

This is super simple to resolve. The DL property named SendOofMessageToOriginatorEnabled needs to be set to False.

Set the property to false like this:

Set-DistributionGroup <DLName> -SendOofMessageToOriginatorEnabled:$false

Hope you like this quick solution. Leave me a comment.

PowerShell: How to display Exchange/AD command results in sorted by Property Names?

I am extremely disappointed with Microsoft PowerShell Modules for Exchange, Active Directory, Azure and others that the results of (e.g., Get-ADUser, Get-Mailbox) commands are not sorted by properties. At times I was looking for specific property value that I don’t remember top of my head. I listed all available properties and search for the property.

e.g., Get-Mailbox <username> | Format-List

If you see the results of the above command, Property and values display at random order. Searching for a property that you don’t remember becomes unnecessarily harder.

So I figured out how to display the results in sorted by property name. You may pipe your command results to this command.

| Select-Object * | Out-String -Stream | Sort-Object

Use this command like this:

Get-Mailbox <username> | Select-Object * | Out-String -Stream | Sort-Object

Here is what I did. Select-Object * selects all the properties, Out-String -Stream converts the results to string and lastly Sort-Object sorts the string results.

My Life got little better.

I didn’t stop there I created a function and added the function to PowerShell Profile, so it will loaded every time. Here is the function:

function Sort-Results { Param([Parameter(ValueFromPipeline=$true)] $ResultObject) ; $ResultObject | Select-Object * | Out-String -Stream | Sort-Object }

Use this function like this:

Get-Mailbox <username> | Sort-Results

Feel free to use this function. If you like this idea, leave me a comment below.

Exchange Online: How to search and delete emails?

This blog explains how to search and delete emails using Microsoft 365 Compliance Center and PowerShell add-in.

First you should know that you can search emails on Exchange Online mailboxes and view the search results in Microsoft 365 Compliance center. BUT you cannot delete the emails from search results. You HAVE to use PowerShell delete (purge) the emails.


Here are the Compliance Center PowerShell Commands used for search and delete.

Search emails in the Mailboxes

First connect to Exchange Online and then Compliance Center in PowerShell:


Next connect to Compliance Center: Replace the UserPrincipalName with yours or Admin account.

Connect-IPPSSession -UserPrincipalName username@company.com

Search email using this command.  You need to specify a mailbox and specific keyword in the search command. Keyword will be searched in Subject, Email body and Attachments.  For help on this New-ComplianceSearch, check it here: Keyword Query Language (KQL) syntax reference | Microsoft Docs

New-ComplianceSearch -Name "Test Content Search" -ExchangeLocation mobius@company.com -ContentMatchQuery "Sample Keyword"

Note: ExchangeLocation parameter can be set to “All” to search all mailboxes if need to. You may also specify a “Distribution List’ to search all mailboxes of members.

Note: You may also search and preview the results at Content Search at https://compliance.microsoft.com/.

Preview the Email Search Results

If you are going to delete the emails, you should check the email search results first to validate emails to be deleted. If you don’t see the email you want to see, you may need to re-do the New-ComplianceSearch command with refined conditions.

To preview the search results, we have to use New-ComplianceSearchAction command with -Preview option. There two steps to preview the search results.

Step-1; Create a Search action.

$SearchAction = New-ComplianceSearchAction -SearchName "Test content Search" -Preview

Here we created new compliance search action with the Preview parameter. Note that Search name is taken from previous New-ComplianceSearch command or copy/paste the Search name from Content Seach at https://compliance.microsoft.com. You should replace the SeachName from your own Seach.

Step-2: Preview the Search Results.

I have wrote this function to format the search results in readble form. You shouild store this function in a PoweShell file I saved as PreviewResults.ps1. This function can be passed parameter using piping the Get-ComplianceSearchAction results.

function PreparePreviewResults
    Param (
    $SearchResults = $SearchResults.Results.Replace('{','').Replace('}','')
    $data = "Location,Sender,Subject,Type,Size,Received Time,Data Link`n"
    $SearchResults | ForEach-Object { $t=""; $_.Split(';').foreach({ $t += $_.Split(":")[1].Trim() +","  }) ; $data += $t + "`n"  }
    Return ($data | ConvertFrom-Csv)

Now dot source this PreviewResults.ps1 file. Replace the path of the PreviewResults.ps1 file in below dot sourcing.

. c:\scripts\PreviewResults.ps1

Now the PreparePreviewResults function in memory, we are going to use this function with this command format. Note that $SeachAction variable has the result object from New-ComplianceSearchAction command in Step-1.

Get-ComplianceSearchAction -Identity $SearchAction.Name | Select-Object Results | ForEach-Object {$_.Results } | PreparePreviewResults | Out-GridView

Delete the Emails

After you validate the emails from the above section, you may delete those email with this simple command. Note that SearchName is same as New-ComplianceSearch command. You should replace the SeachName from your own Seach.

$SearchAction = New-ComplianceSearchAction -SearchName "Test content Search" -Purge -PurgeType HardDelete -Force

Above command will start deleting the emails from the mailbox(es). You can check the status fo the delete operation with this command. Note we used $SearchAction variable used in above command.

Get-ComplianceSearchAction -Identity $SearchAction.Name | Select-Object SearchName,Results,Errors

I hope this is helpful document for you. You may leave a comment of “Thanks” or ask any questions.

This Group Policy object (GPO) is inaccessible because you do not have the read-level permission on it

If you lost permissions to a GPO, obviously you cannot edit the GPO in Group Policy Management Console (GPMC). You would get this error: This Group Policy object (GPO) is inaccessible because you do not have the read-level permission on it.

Don’t you worry. There is an easy fix as long as you are a domain admin.

  • Open ADSIEdit.msc console
  • Right click on ADSI Edit and select “Connect to…”. Choose “Default Naming Context” and click OK.
  • Expland to ADSI Edit >>> Default Naming Context (domain.com) >>> DC=company,DC=com >>> System >>> Policies
  • Find the GUID of the GPO you lost access in Group Policy Management Console. Select the GUID of the Policy under CN=Polices OU.
  • Right click on Policy and choose Properties.
  • Select Security Tab and Click Advanced Button.
  • Take ownership of the policy by changing the owner to yourself (or better to Domain Admins). Close the properites dialog box.
  • Right click on the Policy and open Properties again.
  • Go to Security Tab. I would suggest to add permissions by copying the default permissions from other policy.
  • You may close the ADSI Edit console.

That’s all. After permissioning try accessing the GPO in GPMC.

GPEdit.msc – Failed to open the Group Policy Object on this computer

I see you end up here because local policy editor (GPEdit.msc) is failed to open and you get this error: Failed to open the Group Policy Object on this computer. You might not have the appropriate rights.

This super easy fix might fix the issue. All you have to do is rename (or delete) the folder named Machine at C:\Windows\System32\GroupPolicy.

I would rename the Machine directory to Machine.old. Then try launching gpedit.msc again.