Friday, January 20, 2017

PowerShell Module to Retrieve ACLs from Different Sources

Hi folks,

In this post I have shared with you about PowerShell module that can be used to manage and report NTFS permissions on disk drives and files and folders. However I was also looking for a nice way to report Active Directory ACLs and ACEs by using PowerShell. The Get-Acl cmdlet wouldn't suffice as it would report extended permissions on AD as ExtendedRight without any clear details. Here you can download PowerShell module that allows you to manage ACLs and ACEs not only on file system but also on printers, registry and most importantly AD.

Just as NTFS module this module needs to be installed to the server or computer on which you are running it. You will need to unzip the downloaded files and copy module and the related files to %Windir%\System32\WindowsPowerShell\v1.0\Modules. Before this you will need to create a folder named  PowerShellAccessControl. The below code should do installation magic.

New-Item "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PowerShellAccessControl" -Type Directory
Copy-Item "C:\Scripts\PowerShellAccessControl\*" "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PowerShellAccessControl"

You can read more about the cmdlets in the module in the link published below as they are described in the article. Before running any cmdlet you will first need to import the module into your PowerShell session:

Import-Module PowerShellAccessControl

There're a bunch of the cmdlets in module, I will show you just couple of the samples that you needed and you will thread your own way.

This command will get AD permission from

Get-ADObject "CN=SERVER01,OU=Servers,DC=CONTOSO,DC=COM"| Get-AccessControlEntry

(you can also use Get-AdUser, Get-ADGroup and other cmdlets from the Active Directory PowerShell module to get AD input object)

Finally, another sample below retrieves permissions for the same object for a particular user or group:

Get-ADObject "CN=SERVER01,OU=Servers,DC=CONTOSO,DC=COM" |Get-AccessControlEntry |Where-Object {$_.Principal -eq "Contoso\ContosoAdmins"}

I will let you explore this module further by yourselves and I hope you will find it to be useful.


Monday, January 16, 2017

Some Additions to My Old ActiveSync Reporting Post

Hi folks,

Couple of years ago I have shared with you this post on the code that can be used for reporting of the ActiveSync devices. It still remains valid. However, I'd love to post here some amendments that may be useful for you.

Firstly, Microsoft has introduced in Exchange 2013 the cmdlet Get-MobileDeviceStatistics which at one point may replace Get-ActiveSyncDeviceStatistics and I won't be surprised that the latter one will be deprecated in one of the next builds or major versions. Therefore I have updated my code using it. And secondly I also wanted to report some more information into my report. I wanted to be able to report user agent and also when the device has successfully synced last time. Therefore parameters LastSuccessSync and DeviceUserAgent have been added to the code. The updated code looks like as below, and I would recommend using it with Exchange 2013 and 2016.

$EasUser=Get-CASMailbox -ResultSize Unlimited |Where-Object {$_.HasActiveSyncDevicePartnership-eq 'True'}
$EasUser | foreach {Get-MobileDeviceStatistics -Mailbox $_.Name | select identity,LastSuccessSync,devicetype,deviceid,DeviceUserAgent,isremotewipesupported,LastSuccessSync} |Export-Csv D:\MessagingMetricsReports\ActiveSyncUsageReport.csv

Again, you can add as many parameters as you want to see in your final report.


Friday, January 13, 2017

Retrieve TPM Module Version Using PowerShell

Hi folks,

I would love to share with you two quick ways to retrieve version of TPM module. What is TPM module and how it helps in BitLocker encryption you can find here.

I found it thanks to this article from Dell. I have adapted this command to retrieve the hostname and version of TPM module installed there. My code looks like below:

Get-WMIObject –class Win32_Tpm –Namespace root\cimv2\Security\MicrosoftTpm |select PsComputerName,SpecVersion

This will produce output as below:

The SpecVersion corresponds to the version of the TPM module. Above is the output for TPM 2.0

Finally, there is a nice way to report it for more than one server remotely. This can be achieved by using TPM management module which has been published here in TechNet gallery. ZIP file can be downloaded from the same link and exported. After which module needs to be imported into PS session. Since in my case I'm trying to report information on TPM module installed on Exchange servers I imported it to EMS session.

The command Get-OSCTPMChip is needed to retrieve information from the computer and can be run against remote computers. For it to work successfully you will need to create variable for credentials.

I have composed the below code to connect to all Exchange 2016 servers in the environment and retrieve server host name and TPM module version:

$Cred = Get-Credential
Import-Module 'C:\Scripts\GetTPMChipsStatus (PowerShell)\GetTPMChipsStatus.psm1'
$Exch2016 = Get-ExchangeServer | where-object {$_.AdminDisplayVersion -like "*Version 15.1*"}
$Exch2016 |foreach {Get-OSCTPMChip -ComputerName $_.Name -Credential $Cred} |select ComputerName,SpecVersion |Export-Csv C:\Scripts\TPMExchangeReport.csv

I hope you will find it useful.


Thursday, January 12, 2017

Sending Messages as Scheduled Task

Hi folks,

I would love to share with you about my recent adventure on configuring scheduled task for running some Exchange-related scheduled tasks using PowerShell. To avoid using excessive permissions for an account that will run the scheduled task I created user account in AD with the default group membership (Domain Users). This account has been granted "Logon as batch job" rights on a server where the scheduled task will run. The script included a line to send results of the script execution to an admin's email address, something like below:

Send-MailMessage -from -to -subject "Scheduled Task Report" -body ($bb | out-string) -smtpServer '' -bodyashtml

However, emails wouldn't arrive. There was nothing in the task to indicate failure of it as it ran smootly. So the following line was added to the beginning of the script:

Start-Transcript -Path C:\Scripts\executionTranscript.txt

And at the end of the script I appended:


When checking execution transcript I would see the error as below:

Send-MailMessage : Mailbox unavailable. The server response was: 5.7.1 Client does not have permissions to send as
this sender
At D:\ML\Scripts\QueueStatus.ps1:16 char:1
+ Send-MailMessage -from -to ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.Mail.SmtpClient:SmtpClient) [Send-MailMessage], SmtpExcept
    + FullyQualifiedErrorId : SmtpException,Microsoft.PowerShell.Commands.SendMailMessage

What it says that service account can send as (of course there should be your sender address here). To resolve this issue scheduled task will need to be reconfigured to run as with granting rights as mentioned above. Alternatively, service account can be mail or mailbox enabled (I would recommend the former) and script updated to send email as service account.

You will need to run the below code to mail-enable the service account:

Enable-MailUser -Identity "CONTOSO\serviceaccount" -PrimarySMTPAddress "" -ExternalEmailAddress ""

Then you will need to reconfigure your code to something as below:

Send-MailMessage -from -to -subject "Scheduled Task Report" -body ($bb | out-string) -smtpServer '' -bodyashtml

I hope you will find this useful when troubleshooting issue as this one.


Resetting IDRAC on Dell Servers

Hi folks,

If you are using Dell R720 or R730 you may have encountered IDRAC, a Java-based tool that allows us to remotely connect to server and manage it from console without a need to go to a datacenter and play with KVM there.

However this is what I once encountered. I saw that the Volume Console Preview shows me black screen while trying to connect to server remotely. In the Virtual Console Preview on the IDRAC page instead of server login page I would see black screen:

When trying to launch remote console I would see the error as below:

To resolve this, you will need to launch Command Line (not PowerShell!) as admin on your server and run the below command:

racadm racreset soft

Give it about 5 Minutes to reset and then login to IDRAC again and in the virtual console section you will see the following in the Virtual Console Preview section:

This indicates that the command has done the magic and you now can click Launch to connect to your server's console remotely.

I hope you will find this helpful.


Wednesday, January 11, 2017

Decommissioning Exchange 2010 and Later Mailbox Servers

Hi folks,

As Exchange 2016 is around and Exchange 2013 has been around even longer many of you are dealing with decommissioning of your Exchange 2010 servers. Another reason for decommissioning 2010 servers is moving to the cloud. Surely this is one of the greatest versions of Exchange and will be greatly missed.

In this post I will focus on decommissioning of Mailbox servers, especially DAG members. You can read this article for more details on decommissioning of Exchange 2010 servers and consideration on every role.

This post assumes that all mailboxes have been moved off servers, otherwise we won't be able to decommission mailbox databases.

First we need to remove every mailbox database copy on the server. As a lazy man I prefer to do it using one code line (two if possible). One liner didn't work for me:

Get-MailboxDatabaseCopyStatus -Server SERVER01 |foreach {Remove-MailboxDatabaseCopy -Identity $_.Name -Confirm:$false}

I got the error as below:

So I ended up feeding database copies to the variable $DBCop, After this I ran Remove-MailboxDatabaseCopy against every DB in the $DBCop variable. The code looks as below:

$DBCop = Get-MailboxDatabaseCopyStatus -Server SERVER01
$DBCop |foreach {Remove-MailboxDatabaseCopy -Identity $_.Name -Confirm:$false}

After mailbox database copies are removed we will need to remove mailbox databases themselves:

$DB = Get-MailboxDatabase -Server SERVER01
$DB |foreach {Remove-MailboxDatabase -Identity $_.Name -Confirm:$false}

You are not mistaken to see Get-MailboxDatabase command with -Server parameter. Though in Exchange 2010 and onward DBs are managed globally, still this command works and retrieves all mailbox DB copies stored on a server, This is ideal for limiting output of mailbox databases to a server which we decommissioning. And I don't want PowerShell to complain me about buffer so I create here $DB variable almost immidiately.

After this we will need to remove every DAG member from DAG. Firstly, we will need to disable DAC mode from DAG:

Set-DatabaseAvailabilityGroup DAG01 -DatacenterActivationMode Off

After this we will need to remove each DAG member by runing this command:

Remove-DatabaseAvailabilityGroupServer -Identity DAG01 -MailboxServer SERVER01 -Confirm:$false

After all of mailbox servers are removed from DAG you can kill DAG object in the AD as well:

Remove-DatabaseAvailabilityGroup -Identity DAG01 -Confirm:$false

Remove CAS array (the only ugly thing about Exchange 2010) object from the AD:

Remove-ClientAccessArray -Confirm:$false

Finally, you will need to uninstall Exchange binaries. For Exchange 2010 this command does the magic: /m:Uninstall

For Exchange 2013 and later you will need to run

setup.exe /m:Uninstall /IAcceptExchangeServerLicenseTerms


Tuesday, January 10, 2017

Changing Your AD Password Via RDP

Hi folks,

Many of you may already know it and therefore please feel free to ignore this little post. However, I have recently learned a nice trick on how to change your AD password via RDP screen. It is especially useful for engineers and admins who admin their Windows servers via RDP Manager or a single RDP conenction (aka MSTSC command).

You will need to run the following command: osk

It will display on-screen keyboard. On your normal keyboard you will need to hit Ctrl+Alt while on the on-screen keyboard you will need to click on Delete.

That will display password change screen. An you know yourself what to do further.


Extracting AD Group Members Using PowerShell

Hi guys,

Imagine you know the name of the distribution list of the AD group which is not mail-enabled and you will need to extract members of it. The below code should come to your help. I personally ran it from the Exchange Management Shell and had AD PowerShell module loaded (which is needed on any machine running Exchange tools anyway. The first line extracts distinguished name of the group into a variable, while the second one is extracting group members (in my case attributes like DistinguishedName and samAccountName (you can change output attributes just as you need). These attributes are dropped into the CSV file.

$Grp = (Get-Group MyGroupName).DistinguishedName

Get-ADGroupMember $Grp |select DistinguishedName,SamAccountName |Export-Csv c:\Scripts\GrpMbr.csv


Monday, January 9, 2017

Capturing Exchange Components Logs

Hi folks,

There are moments in our lives when we need to perform some troubleshooting of our Exchange environment. You can increase loggi

You can read more about logging for Exchange components in this article

For components list and how it has changed in Exchange 2013 you can refer here

If you want to retrieve list of all Exchange components you can run this command:

Get-EventLogLevel -Identity "MSExchange*" |sort Identity

In my case I needed to perform troubleshooting of EWS so to check its logging level you will need to run the following command:

Get-EventLogLevel -Identity "MSExchange Web Services\Core"

Depending on the logging detail level required you will need to run Set-EventLogLevel command and specify logging level depending on the logging details required. The possible logging levels that you can set are: 0 (Lowest), 1 (Low), 3 (Medium), 5 (High), and 7 (Expert). In my case I needed all details so I ran the following command:

Set-EventLogLevel -Identity "MSExchange Web Services\Core" -Level 7

After completing your troubleshooting activities you will need immidiately revert setting back to the default (Lowest or 0 in our case)

Set-EventLogLevel -Identity "MSExchange Web Services\Core" -Level 0


UM Certificate Configuration in Exchange 2013 and Later

Hi folks,

Just wanted to quickly share with you about the configuration of Exchange certificate for Unified Messaging on Exchange 2013 and 2016 servers. In Exchange 2007 and 2010, as you remember, UM was a separate role and Set-UMServer was the command which did all the configuration magic. This has changed in Exchange 2013 as UM service has been spread between the Mailbox and CAS roles. Now Mailbox server run UM service which is manipulated by the Set-UMService cmdlet, while CAS service runs UM Call Router service which accepts all the SIP traffic and proxies it to the UM service on the Mailbox servers that hosts active DB copy for the mailbox where the call is being routed to. You can read more about UM in Exchange 2013 here. On the Exchange 2016 both of the services mentioned above are hosted on the Mailbox role.

So in order to configure certificate for UM on the Exchange 2013 and later server you will need to enable startup mode for UM and UM Call Router services either to TLS (for integration with Lync or Skype for Business) or Dual mode:

Set-UMService UMSRV01 -UMStartupMode Dual

Set-UMCallRouterSettings -Server UMSRV01 -UMStartupMode Dual

After which you will need to import certificate from the file and enable it for the appropriate services:

Import-ExchangeCertificate -FileData ([Byte[]]$(Get-Content -Path certfile.NET.pfx -Encoding byte -ReadCount 0)) -Password:(Get-Credential).password

Enable-ExchangeCertificate -Thumbprint XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -Services UM,UMCallRouter

Don't forget that you will need a separate cert for each of the Exchange servers with a server hostname as subject name.