≡ Menu

PowerShell: Find my public IP

Every computer requires a public IP address to connect to the internet. Some individuals/organizations buys public IP addresses from their Internet Service Provider(ISP) and some uses ISPs proxy to connect to the internet. In any case, traffic(web) from your computer need to flow through a public IP address in order to communicate with web sites/servers/computers that are in the internet. This article will show a quick PowerShell way of finding this public IP address.

There are many websites like whatismyip.com etc which can give you this information. It can be queried from any programming languages using REST API provided as well. For demonstration, I am using http://ipinfo.io services and I will query it using Invoke-RestMethod (irm in short) cmdlet in PowerShell.

Invoke-RestMethod -Uri "http://ipinfo.io"

And the output will look similar to below.

I have hidden the information intentionally, but when you run this command from PowerShell window on your computer, you should see the IP address and other details. You can access these details individually as well if you like.

#To get IP address only
(Invoke-RestMethod -Uri "http://ipinfo.io").IP

#To get City Name
(Invoke-RestMethod -Uri "http://ipinfo.io").City

#To get Country Name
(Invoke-RestMethod -Uri "http://ipinfo.io").Country

One thing to keep in mind here is, the City & Country information may look incorrect sometimes as it is totally depends on how your internet provider is routing the traffic. Also if your computer is using any VPN to connect to internet, these details will change as well.

Hope this information is useful.

{ 0 comments }

Install DFS or DFS-R Management tools using PowerShell

DFS Management console is used for managing DFS namespaces and DFS-R replication. You can install it in a Windows server or desktop by running below command which will install DFS Management Console & related PowerShell modules.

add-WindowsFeature -Name RSAT-DFS-Mgmt-Con

Above command will install the DFS Management tools on the local computer, you can use the same command with a combination of PowerShell remoting to install on a remote server.

Invoke-Command -ComputerName tiblab.local -ScriptBlock { add-WindowsFeature -Name RSAT-DFS-Mgmt-Con }

Do you have any other scenario to install Windows Feature and not sure how to do it with PowerShell?; post in the comments section. We will do our best to get back.

{ 0 comments }

PowerShell: Simple way to generate random passwords

In this post we will see the simplest way I came across to generate random passwords using PowerShell. There are other methods available with large features set but this one is good enough for most requirements

First let us look at the simplest way. The GeneratePassword method of System.Web.Security.Membership class simplifies the password generation.

Add-Type -AssemblyName System.Web
[System.Web.Security.Membership]::GeneratePassword(8,3)
Generate random password

As you can see from the above screen, these 2 simple lines of code generated a random password of length 8.

The GeneratePassword() method takes 2 arguments. First one is length of password and second one is number of non-alphanumerics you want in the random password. In my example, I have provided 8 as password length and 3 as number of non-alphanumeric characters I need.

You can use this approach to generate as many number of random passwords you want. Look at the below example.

1..10 | % { [System.Web.Security.Membership]::GeneratePassword(8,3) }
Generate multiple random passwords

There are other ways available as well. I am sharing some of the links that I came across.

  1. https://activedirectoryfaq.com/2017/08/creating-individual-random-passwords/
  2. https://gallery.technet.microsoft.com/scriptcenter/Password-Generator-using-0f99f008
  3. https://4sysops.com/archives/generate-complex-passwords-with-powershell/
  4. https://gist.github.com/indented-automation/2093bd088d59b362ec2a5b81a14ba84e

Hope this article helps. Let me know if you come across any easy and better way.

{ 1 comment }

Information in this article helps you to query a certificates expiry date, issued date, subject, issuer and other details remotely using PowerShell. Another good thing is, you don’t need admin rights to do that.

There are cases where you want to continuously monitor validity of a certificate remotely. For example, you have a bunch of web servers for which you want to monitor the certificate used by Web Service or you have a rest API which is using SSL cert and you want to monitor and alert when it expires. This script will solve such issues. Since this script relies on TCP steam data to validate the certificate details, it doesn’t need administrator rights on remote computer.

NOTE: If you are looking for a script that checks the expiry dates of all certificates in your remote systems cert store, then this script is of no use. The purpose of this script is to get certificate details using using application ports remote(like 443 for HTTPS)

This script requires two arguments,

  1. ComputerName : It can be a single computer name or list of computer names separate by coma.
  2. Port: Port number on which your application listens. For example 443 for HTTPS application. This parameter is optional and defaults to 443 when not specified.
  3. ExportToCSV: This switch parameter helps you export the output to CSV file for your convenience.

Code:

Copy below code to a file and save it as Get-SSLCert.ps1.

[CmdletBinding()]
param(
[parameter(Mandatory=$true)]
[string[]]$ComputerName,
[parameter(Mandatory=$true)]
[int]$Port = 443,
[switch]$ExportToCSV
)

$Outarr = @()
foreach($Computer in $ComputerName) {
Write-Host "Working on retrieving cert for $Computer" -ForegroundColor Green
try {
$tcpsocket = New-Object Net.Sockets.TcpClient($Computer,$Port)
$tcpstream = $tcpsocket.GetStream()
$sslStream = New-Object System.Net.Security.SslStream($tcpstream,$false)
$sslStream.AuthenticateAsClient($computer)
$CertInfo = New-Object system.security.cryptography.x509certificates.x509certificate2($sslStream.RemoteCertificate)
$SubjectName = @{Name="SubjectName";Expression={$_.SubjectName.Name}}
$OutObj = $CertInfo | Select-Object FriendlyName,$SubjectName,HasPrivateKey,EnhancedKeyUsageList,DnsNameList,SerialNumber,
Thumbprint,NotAfter,NotBefore,@{Name='IssuerName';Expression = {$_.IssuerName.Name}}
if($ExportToCSV) {
$Outarr += $OutObj
} else {
$OutObj
}

} catch {
Write-Warning "Unable to get cert details for `"$Computer`". $_"
}
}

if($ExportToCSV) {

$Outarr | Export-Csv c:\certdetails.csv -NoTypeInformation
}

Usage:

Query certificate details of single web server.

.\Get-SSLCert.ps1 -ComputerName google.com -Port 443

Query certificate details of multiple web server

.\Get-SSLCert.ps1 -ComputerName google.com,google1.com,yahoo.com -Port 443

Export cert details to CSV

.\Get-SSLCert.ps1 -ComputerName google.com,google1.com,yahoo.com -Port 443 -ExportToCSV

Query certificate details of another application which uses TLS

.\Get-SSLCert.ps1 -ComputerName myserver.fqd.com -Port 123

Output

Hope this helps.

 

{ 1 comment }

VMware ESX host stores good amount of information about Hardware and it sensor’s values. These values are extremely useful in troubleshooting any peformance/hardware issues. In this article, I will show you how to query these values using PowerCLI.

This function assumes that you already connected to VCenter. You need to provide list of VMhost names as parameter to this script. The script also takes optional -ExportToCSV in case you want to export the data to CSV file for further processing.

Code:

function Get-VMHostSensorsInfo {
[CmdletBinding()]
param(
    [parameter(mandatory=$true)]
    [string[]]$VMHostName,
    [switch]$ExportToCSV
)

    $OutArr = @()
    foreach($VMHost in $VMHostName) {
        Write-Verbose "Fetching data from $VMHost"
        try {
            $VMHostObj = Get-VMHost -Name $VMHost -EA Stop | Get-View
            $sensors = $VMHostObj.Runtime.HealthSystemRuntime.SystemHealthInfo.NumericSensorInfo
            foreach($sensor in $sensors){
                $object = New-Object -TypeName PSObject -Property @{
                    VMHost = $VMHost
                    SensorName = $sensor.Name
                    Status = $sensor.HealthState.Key
                    CurrentReading = $sensor.CurrentReading 
                } | Select-Object VMHost, SensorName, CurrentReading, Status
                $OutArr += $object
            }
         } catch {
            $object = New-Object -TypeName PSObject -Property @{
                VMHost = $VMHost
                SensorName = "NA"
                Status = "FailedToQuery"
                CurrentReading = "FailedToQuery"
            } | Select-Object VMHost, SensorName, CurrentReading, Status
            $OutArr += $object
         }

    }

    if($ExportToCSV) {
        Write-Verbose "Exporting to c:\temp\sensorsinfo.csv"
        $OutArr | export-csv c:\temp\sensorsinfo.csv -NoTypeInformation
    } else {
        return $OutArr
    }
}

Usage:

Using this code is very simple. First open your PowerCLI and connect the VCenter using the credentials that can query the host information. Then copy and paste the above function to the PowerCLI shell and start running commands below as per your needs.

Get Sensors status of single host

Get-VMHostSensorsInfo -VMHostName server1

Get sensors status of multiple hosts

Get-VMHostSensorsInfo -VMHostName server1, server2

Get sensors status of hosts from file

Get-VMHostSensorsInfo -VMHostName (Get-Content c:\temp\servers.txt)

Export sensors status to CSV

Get-VMHostSensorsInfo -VMHostName (Get-Content c:\temp\servers.txt) -ExportToCSV

Hope this helps…

{ 2 comments }

PowerShell: Creating self signed certificate

Let us learn today how to generate a self signed certificate quickly using PowerShell. There are many ways available to do this but using New-SelfSignedCertificate is much easier.

You need to have at least Windows Server 2012/Windows 8 to use this approach. Once the cert is generated you can use it anywhere you want.

First you need to run below command to generate the certificate. Subject name can be anything of your choice. You can use DnsName parameter if you want.


$cert = New-SelfSignedCertificate -Subject "techibee-test-cert"

It creates the cert by default in LocalMachine\MY cert store. If you wish to create in any other store, you can do so.

Now you can export it to a file(PFX format) using Export-PFXCertificate cmdlet. To export the cert, password is mandatory.

$password = ConvertTo-SecureString "mypassword" -AsPlainText -Force

Export-PfxCertificate -Cert $cert -FilePath c:\mycert.pfx -Password $password

The above command will export the cert in PFX format with password protection and it will be placed in c:\ drive with mycert.pfx name. Change FilePath values if you want to store at different location.

Now you can use this cert for your testing etc.

Below is the screenshot of the execution.

Hope it helps.

{ 3 comments }

PowerShell: Verify or test AD account credentials

We prompt for credentials in many of our scripts. Have you ever wondered if the entered credentials is right or wrong? It is always good idea to verify that entered credentials is correct before proceeding with further execution of the script.

The function discussed in this article will provide a easy way to verify if the entered credentials are valid or not. This function uses classes and methods in System.DirectoryServices.AccountManagement name space, especially ValidateCredentials method.

The Test-ADCredential function takes PSCredential argument as input. This is optional one. If you don’t specify it, a prompt will appear for you enter the credentials. That means we can use this function in our scripts as well as for adhoc testing needs.

Code

function Test-ADCrential{
    [CmdletBinding()]
    param(
        [pscredential]$Credential
    )
    
    try {
        Add-Type -AssemblyName System.DirectoryServices.AccountManagement
        if(!$Credential) {
            $Credential = Get-Credential -EA Stop
        }
        if($Credential.username.split("\").count -ne 2) {
            throw "You haven't entered credentials in DOMAIN\USERNAME format. Given value : $($Credential.Username)"
        }
    
        $DomainName = $Credential.username.Split("\")[0]
        $UserName = $Credential.username.Split("\")[1]
        $Password = $Credential.GetNetworkCredential().Password
    
        $PC = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Domain, $DomainName)
        if($PC.ValidateCredentials($UserName,$Password)) {
            Write-Verbose "Credential validation successful for $($Credential.Username)"
            return $True
        } else {
            throw "Credential validation failed for $($Credential.Username)"
        }
    } catch {
        Write-Verbose "Error occurred while performing credential validation. $_"
        return $False
    }
}

Output

Run the function without arguments and it will prompt you to enter credentials

Test-ADCredential

Run the function by passing credential object as argument and it will return the output straightway.

$myCreds = Get-Credential
Test-ADCredential -Credential $Mycreds

Do you have any questions about how this function works? Please write in the comments section, we will get back on that.

{ 1 comment }

Python: Get current date and time

Today’s post is about finding today’s date and time using Python. This script queries local system for today’s date and time in local time zone.

We will be using python built-in module called datetime for this purpose. This module has a function called now() which will return a date time object. Let see how it looks like.

import datetime as dt
dt.datetime.now()

If you execute above lines of code from Python REPL, you will see that it returns a date time object as shown below.

As you can see in the output it returned datetime in object format. It is very convenient to use this object if you are going to consume this further in your scripts. However, at times we want to print the time that humans can easily understand. For example, you want to print date time in MM-DD-YYYY format. To do that we can use strftime() method which is available on the datetime object. Let us see how to use it.

import datetime as dt
date = dt.datetime.now()
print("Today's date time : {0}".format(date.strftime("%d-%m-%Y %H-%M-%S")))
print("Today's date time : {0}".format(date.strftime("%D %T")))

Execute the above code form repl and you will see the below output.
We are using strftime() method to format the date time the way we want. If you want to explore other formats available with strftime(), refer the below table(source: python.org)

 

Directive Meaning Notes
%a Locale’s abbreviated weekday name.
%A Locale’s full weekday name.
%b Locale’s abbreviated month name.
%B Locale’s full month name.
%c Locale’s appropriate date and time representation.
%d Day of the month as a decimal number [01,31].
%H Hour (24-hour clock) as a decimal number [00,23].
%I Hour (12-hour clock) as a decimal number [01,12].
%j Day of the year as a decimal number [001,366].
%m Month as a decimal number [01,12].
%M Minute as a decimal number [00,59].
%p Locale’s equivalent of either AM or PM. (1)
%S Second as a decimal number [00,61]. (2)
%U Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0. (3)
%w Weekday as a decimal number [0(Sunday),6].
%W Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0. (3)
%x Locale’s appropriate date representation.
%X Locale’s appropriate time representation.
%y Year without century as a decimal number [00,99].
%Y Year with century as a decimal number.
%Z Time zone name (no characters if no time zone exists).
%% A literal '%' character.

 

Notes:

  1. When used with the strptime() function, the %p directive only affects the output hour field if the %I directive is used to parse the hour.
  2. The range really is 0 to 61; this accounts for leap seconds and the (very rare) double leap seconds.
  3. When used with the strptime() function, %U and %W are only used in calculations when the day of the week and the year are specified.

Hope this article is helpful.

{ 0 comments }

PowerShell: Get Domain NetBIOS name from FQDN

How to find NetBIOS name of a Active Directory domain if you know the FQDN is something we will explore in this post. There are multiple ways to achieve this and let us see two of the popular and easy ways to do it.

We can get this information using two ways.

  1. Using Active Directory PowerShell cmdlet Get-ADDomain
  2. Using [ADSI] Powershell accelerator

Using Get-ADDomain.

To use this cmdlet you should have ActiveDirectory module installed as Get-ADDomain is part of this module. Once the module is imported with Import-Module cmdlet, you can get the NetBIOS domain name by passing FQDN as shown below.

Import-Module ActiveDirectory
(Get-ADDomain -Server techibee.local).NetBIOSName

Using [ADSI] PowerShell accelerator

Getting the NetBIOS name using Get-ADDomain cmdlet is very straightforwad and easy, but you cannot have this module installed on all the machines you want to run your script from. For example, you are scheduling a script on all computers in your environment in which you want to get the NetBIOS name, then it is practically impossible to deploy/maintain the module on all computers. Also this module requires Active Directory Web Services to be available which is available from Windows 2008 R2 onwards. If your domain has legacy DCs, Get-ADDomain will not work for you. The below sample code will help you such situations. It don’t have any dependency on the external modules, it relies on .Net classes to get the NetBIOS name from domain FQDN

([ADSI]"LDAP://techibee.local").dc

Do you know any other easy way? Please write in the comments section. It will be added to this article.

 

{ 2 comments }

[SOLVED] Wi-Fi on Windows 10 is slow

You may experience slow internet connection on your Windows 10 PC when you have more than one active network connection. This article helps you to resolve such issues and make the internet browsing experience faster.

You might wondering why a computer need multiple network connection, but yes, it is a possible scenario. Some people use Wi-Fi connectivity for browsing and LAN connection for connecting to work place network etc. So, it is quite a possible scenario.

The issue will surface when one of the connections has internet access and other connection doesn’t have. You will start noticing internet connection taking more time and your browser spends time at Resolving host state(you can notice this chrome) during this process. If you ask any Windows expert, they will say change the network order to ensure adapter with network connection is first in the list.

In older version of windows, there is a concept of network adapter order. That means OS will chose first one in the list to perform network related operations and if it fails goes to the next one. See below image for better understanding.

Image source: Microsoft Networking Blog

But this is improved in Windows 10 and now there no concept of ordering the network as OS is capable of taking the intelligent decisions based on a few factors. However when it comes to DNS name resolution, the components still looks for ordering (source: https://blogs.technet.microsoft.com/networking/2015/08/14/adjusting-the-network-protocol-bindings-in-windows-10/) and they use InterfaceMetric property of the adapter to make the choice. The lower this number, the higher the preference for dns name resolution.

So, this is problem we are hit with. Generally Wi-Fi networks InterfaceMetric value is more than LAN adapter value. So, the name resolution process will try to use the DNS servers configured in LAN adapter first to resolve the internet names like google.com etc. When it fails, then it will goto the next adapter i. e Wi-Fi adapter. The problem is worse when you have more than 2 adapters (possible when you install Hyper-V role on Windows 10).

I tried following the suggestion at Microsoft blog(https://blogs.technet.microsoft.com/networking/2015/08/14/adjusting-the-network-protocol-bindings-in-windows-10/) but it didn’t work for me. I believe the logic in that blog to determine the existing order is incorrect. So, I did a bit of experimenting and came up with below approach which worked great for me. In my case, I have more than 2 adapters as I am running Hyper-V role.

First we need to check what is the existing metric values for the adapters. We can do it by running below command from a PowerShell window with Administrator rights. Make a note of the current values so that you can revert to original settings if the fix is not working for you.

Get-NetIPInterface -AddressFamily IPv4 | select ifIndex,ifAlias,interfaceMetric

As you can see, my Wi-fi adapter metric is 50 and there are other adapters that value less than 50. That means Operating System will first try to resolve the name using the DNS servers configured on those adapters and it comes to Wi-Fi if it gets no response. Since they are private networks, resolving internet names will not work through them. Now we need to change the metric to a value lower than these adapters. So, I decided to set the metric value of Wi-Fi adapter to 10 so that it becomes less than other adapters. I have used below command to do this.

Set-NetIPInterface -InterfaceAlias "Wi-fi" -InterfaceMetric 10

Once this is executed without issues, you can restart the box and you will notice internet experience is back to normal. If not, revert back to old value to running the same command with original InterfaceMetric Value.

Please note that this is personal experience and may or may not work in your case. So, understand the scenario of your problem and decide if this fix will help you. Please write in comments section if this fix helped you or not. If you know any other fix, please share it.

 

 

 

{ 1 comment }