How to check certificates expiration date using PowerShell

A best practice is having an automate process to check the certificates expiration date, let’s say 60 days before their expiration, in that way proactively you can start the process to request a new certificates, besides of your company request process this article will help you identify those certificates with expiration date before 60 days.

First things first, lets identify where the certificates are located. You can use this cmdlet in PowerShell to see how many containers you have:

PS C:\> Get-ChildItem -Path Cert:\*

At this point we will focus on the LocalMachine because in your servers the most important are the machine certificates.

 PS C:\> Get-ChildItem -Path Cert:\localmachine

As you can see in the list, we have the folder My, here we will find the certificates that we use for different applications, for example SQL, Exchange, Web, Skype for business, etc.

PS C:\> Get-ChildItem -Path Cert:\localmachine\my

And we get the list of certificates

You could use the Format-List option to see all details for these certificates as follow

As you can see in detail, we have the parameter NotAfter, this is the most important for us at this moment because it indicates the expiration date, so let’s get this information for these certificates.

PS C:\> Get-ChildItem -Path Cert:\localmachine\my | select NotAfter

With this line we will see only the expiration date for all certificates

Now let’s filter for the next 60 days using the Get-Date functions as follow

PS C:\> Get-ChildItem -Path Cert:\localmachine\my | ?{$_.NotAfter -lt (get-date).AddDays(60)}

If you remember, I had three certificates but only two have already expired or will expire.

If you want to see all details you can add the Format-List option at the end after a pipe “|”

PS C:\> Get-ChildItem -Path Cert:\localmachine\my | ?{$_.NotAfter -lt (get-date).AddDays(60)} | fl

From here you could automate this process and run every week and send the report to your team, also you can play with the different options to get only the expiration day, subject, Thumbprint, etc.

Thanks for reading

Invite me a beer!

Choose an amount


Your contribution is appreciated.


How to change the UPN on Windows domain

How to change the UPN on Windows domain.

When you are ready to migrate to o365 and realize that your domain is not routable because more than 10 years ago when the domain was created they used .local extension, now a lot of years later you have to fix it.

Another scenario is when the company A acquires Company B and its time to unify everything, you have to change UPN also.

In my opinion is more common the first scenario, the second one is an option though.

The process to complete this setting is as follow:

In your domain controller go to Active Directory Domains and Trusts

Right click on Active Directory domains and trusts and select properties

The UPN suffixes window will appear and here we can add an alternative Suffix as shown below:

Click on Add, then OK to register the alternative domain name.

Now we have another UPN suffix in our domain, we can change this domain name either to specific users or the whole domain users.

In this case lets change to a specific user. To do so, open Active Directory Users and Computers and find a user to change the UPN.

Right click and select properties, then click on Account tab and click on the domain name

As you can see on the figure, now we have available the new domain name, then select the new UPN suffix and click on OK.

Lets validate the change using PowerShell:

As you can see on the UPN attribute, we have now the correct domain name.

So, if you need to change the same for all users in your domain you can do in different ways.

Here you have an script to do so.

# How to change the UPN by Tony Gonzalez

#Lets create a variable to assign the users to affect.

#In case you can modify only few users, you can assign those users to this variable

$Users = Get-ADUser -Properties * -Filter * -SearchBase “OU=UK,DC=TonySolutions,DC=com”

#$Users = Get-ADUser -Properties * -Filter *

Write-Host “The total of users to change the UPN are: $($Users.Count)” -ForegroundColor Yellow

Write-Host “Are you sure to continue? (Y/N)” -ForegroundColor Yellow

$Continue = Read-Host

if($Continue -like ‘y’)


    foreach($User in $Users)


        $NewUserUPN =  $User.UserPrincipalName.Replace(“”,””)

        #Notification about the user we are working on

        $Name = $User.SamAccountName

        Write-Host “Working with $($Name)”

        #Applying the change

        Set-ADUser $Name -UserPrincipalName $NewUserUPN

        #Validating the change

        $Sam = $User.SamAccountName

        Get-ADUser $Sam -Properties UserPrincipalName





 Write-Host “No changes made to the $($Users.Count) Users” -ForegroundColor Green


Thanks for reading!

Invite me a beer!

Choose an amount


Your contribution is appreciated.





How to configure a NAT switch on Hyper-V

Everyone has used a lab environment either to test new technologies or to have a safe environment to test scripts or any other configuration, for some hypervisors like VMWare you need to have licenses to use networking devices like switches.

On Oracle VirtualBox you need to have advance networking and Linux skills to create some Virtual machines using Linux as Operating system and then create the routers and switches.

After you have this Linux computers and configure the Switch or router role then configure your internal network.

Another option is creating a Windows server with the NAT role installed, but again we need to create another computer that needs storage on the Hard drive, memory and CPU from the host, sometimes we don’t have enough resources for this.

Fortunately, we have another free option using Hyper-V and creating a NAT switch, in my experience using this option my environment is faster than using another computer as NAT server.

NOTE: If you need help to install the Hyper-V feature on Windows 10 follow this process How to configure Hyper-V on Windows 10

This is my virtual environment with three virtual computers connected to a default switch:

The complete design is as follow:

That means the host cannot provide internet access to the Virtual machines because we are assigning a different IP range.

In order to solve this problem lets create a new virtual switch and configure it as NAT switch.

To complete the configuration open PowerShell ISE as administrator on the host computer.

We are creating the switch as shown below:

The next sped is create the virtual interface for this network

And finally, we need to create the network

Make sure you connect the network interface of the Virtual machines (In my case VM1, VM2, VM3 and VM4) to the NAT Switch, immediately these computers will have internet access.

Thanks for reading!

Invite me a beer!

Choose an amount


Your contribution is appreciated.





How to connect to Exchange Online via PowerShell using a Mac

Is the first time using a Mac and I was wondering if I’m able to connect to exchange online using a computer with another operating system different as windows.

The first attempt was with Powershell Core and I downloaded the version 6.2.1 from to get the package to install on my Mac.

Once I got the package I started with the installation

Powershell has been installed successfully, then its moment to try the connection to exchange online

As you can see in the image, I got an error: “New-PSSession : This parameter set requires WSMan, and no support WSMan client library was found, or PowerShell quits with an unhandled exception

Researching I figured out there is another way to install PowerShell using HomeBrew (

To install, open Terminal and paste these lines:

/usr/bin/ruby -e “$(curl -fsSL”

Press Enter

Input your admin password, then xcode will be installed.

HomeBrew installation will be completed, then now let’s install PowerShell.

paste the follow line: brew cask install powershell to start the installation

Input again the admin password

And PowerShell has been installed on my Mac! Now I will try to connect to Exchange online.

Use the follow command to save your o365 credentials in a variable: $UserCredential = Get-Credential

then save the session information in another variable called $Session:
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri -Credential $UserCredential -Authentication Basic -AllowRedirection

As you can see, the error does not appear anymore!
The next step is start the session using: Import-PSSession $Session -DisableNameChecking

We can see that PowerShell is importing all exchange online cmdlets on this computer. To confirm, let’s get all mailboxes in my tenant.

And that’s all! I hope this process helps to all Mac users.

Tony Gonzalez

Some special operators in PowerShell: $($Variable), @( ), &, S_., %, ?

There are some operators that they are not common in PowerShell and we have problems to figure out the logic when we are reading a script written by another person.

For example $($Variable) operator. This is a subexpression operator that always will evaluate first the expression contained into the parenthesis and return the value as an array, and therefore you can use this information directly. Let’s see the follow example:

$c = Aduser 430001150
The variable $C contains all the information for this Active Directory object, and therefore If I want to know only the first name and last name I can write this:

Write-Host “The firstname is: $($c.GivenName)-ForegroundColor Yellow
Write-Host “The firstname is: $($c.Surname)-ForegroundColor Yellow
And the output will be:
The first name is: Tony
The last name is: Gonzalez

@() Array expression

Returns the result of one or more statements as an array, when you have the construct @() you are creating an array without any elements at all. Otherwise, if you add elements to the array they will have an index;

$array = @()   #We declare this variable as array
$array = @(1,2,5,6,9,”Hello”,”World”)   #We are adding elements to the array, the first element has the index 0, in this case has the value 1.
If we want to know what information contains this array:

PS C:\> $array
& Call operator. We use this operator to run a command, script, or script block. For example:

PS C:\> $b = “Get-ChildItem”
If we execute this value to see the result, will be the string stored in quotes.

PS C:\> $b
But if we put the call operator & we are going to get another result

PS C:\> & $b
    Directory: C:\
Mode                LastWriteTime     Length Name                                                                                                                                                
—-                ————-     —— —-                                                                                                                                                 
d—-         12/7/2016   2:52 PM            Dell                                                                                                                                                  
% Is an Alias for the command let ForEach-Object is a loop who returns each pipeline object one after the other. Which means that you can use both in a sentence.

? Is an alias for the command let Where-Object. We use this sentence to select an object from a collection.

In both aliases we can use $_. To reference to a filed into the result. For example:

PS C:\> Get-ChildItem “C:\” | ?{$_.Name -eq “temp”}
    Directory: C:\
Mode                LastWriteTime     Length Name                                  
—-                ————-     —— —-                                  
d—-          2/1/2018  11:51 AM            temp                                   

These are only some of the operator that sometimes we do not know how they mean when we are analyzing a script that has been created by another person, but obviously, there are much more. 

I will put another post with a little more. 

How to count members in an Active Directory group using PowerShell

   There are different methods to get this information when the group is small, but the problem shows up when a group contains thousands of members.

The first cmdlet that I tried was:
$members = Get-ADGroupMember -Identity “Group Name”

The idea is execute the follow line:

But I got this error: “The size limit for this request was exceeded”

And the same with the follow cmd lets:
  • Get-ADGroupMember -Identity “Group Name” > C:\Temp\members.txt (even exporting the result to a csv file).
  • Get-ADGroupMember -Identity “Group Name” | Measure-Object
  • Get-ADGroupMember -Identity “Group Name” | Measure-Object | select count

The command that worked properly for me was:
$members = Get-ADGroup -Identity “Group Name” -Properties Members

I my case, I ran this command for a group that contains more than 7k members. 

How to reuse commands in PowerShell

Sometimes you have a repetitive tasks in PowerShell, for example purging emails in Exchange, or maybe you just wanted to polish or correct a command you wrote.

There are some different ways to do so:

1. Arrow Up and Arrow Down, press those keys to scroll up or down in your command history and select the desired command to work with.

2. Using F5 and F8 you are able to the same as above (arrows keys).

3. Using F7 and then scrolling up or down using arrow up and down to select the command into the history list. This option is my favorite. With F9 you can enable the numbers if you want to use a number stead of press enter.

With (Alt)+(F7) you can clear the command history and start from scratch.

In addition, the command history only keeps 50 commands by default, but you can modify this value in your profile.

I hope these tips can help you in your day-to-day.

Best regards.

Tony Gonzalez.