≡ Menu

PowerShell: Search for a value in Array

If your array has a bunch of items and you would like to verify if the given string/number is found in the array, here is the quick tip for you.

There are actually 2 ways of doing it.

Using -In operators

$sample = @(1,2,3,4,5,6)
2 -in $sample # returns True
9 -in $sample # returns False
Using -in operator

Using Contains method on the array

Alternative to -in operator is using Contains method on the array object itself. This is equally useful.

Using Contains method

Both of the above approaches works well with strings too. In case you are using strings, note that Contains method is case sensitive and -in operators is not case-sensitive. Look at the below code for example.

$sample = @("one", "two", "three")
$sample.Contains("one") # returns True
$sample.Contains("oNe") # returns False
"one" -in $sample # returns True

"One" -in $sample # returns True

In case you want case sensitive search with -in operator use -cin instead

Hope this helps you.

{ 2 comments }

The subject says it all. Many of the system admins know that flipping a registry key will enable or disable RDP connectivity on a Windows Server or desktop. However, modifying the registry is not always convenient. For those out there who thinks there should be much easier way, this post is for them 🙂

You can enable RDP on a remote host by simply running the below two lines.

$tsobj = Get-WmiObject -Class Win32_TerminalServiceSetting -Namespace Root\CimV2\TerminalServices -ComputerName SERVER01
$tsobj.SetAllowTSConnections(1,1)

You can also disable it using the below method.

$tsobj = Get-WmiObject -Class Win32_TerminalServiceSetting -Namespace Root\CimV2\TerminalServices -ComputerName SERVER01
$tsobj.SetAllowTSConnections(0,0)

Do you care to check if it is currently enabled or disabled before acting? Use the below code.

$tsobj = Get-WmiObject -Class Win32_TerminalServiceSetting -Namespace Root\CimV2\TerminalServices -ComputerName SERVER01
$tsobj.AllowTSConnections

Wondering what are the 2 arguments for SetAllowTSConnections function? The first one represents AllowTSConnections(0 – disable, 1 – enable) and the second one represents ModifyFirewallException (0 – don’t modify firewall rules, 1 – modify firewall rules). You can read more about it at https://docs.microsoft.com/en-us/windows/win32/termserv/win32-terminalservicesetting-setallowtsconnections

Hope this article is helpful for you. Feel free to write in the comments section if you have any questions.

{ 0 comments }

In today’s article, I will take you through a PowerShell script that helps to get the list of files that are older than a given number of days. This script searches for files in a given directory path and calculates the age of each file. We can apply filters on it get the files older than we need.

The script is simple and self-explanatory, so we are not going to spend much time taking you through part of the scripts. The only one thing I want to highlight is it gives the age of files only and not directories in the path provided to the script.

Below is the script and it has only one mandatory input parameter, Path. You just need to provide the directory path in which you want to search for a list of files older than some days. We can filter the output further down to specify the days we are interested in. You will see this in the examples section below.

Save the below code into Get-Olderfiles.ps1

Code

[CmdletBinding()]
param(
    [Parameter(Mandatory=$true)]
    [string]$Path
)

#Check and return if the provided Path not found
if(-not (Test-Path -Path $Path) ) {
    Write-Error "Provided Path ($Path) not found"
    return
}

try {
    $files = Get-ChildItem -Path $Path -Recurse 
    foreach($file in $files) {
        
        #Skip directories as the current focus is only on files
        if($file.PSIsContainer) {
            Continue
        }

        $last_modified = $file.Lastwritetime
        $time_diff_in_days = [math]::floor(((get-date) - $last_modified).TotalDays)
        $obj = New-Object -TypeName PSObject
        $obj | Add-Member -MemberType NoteProperty -Name FileName -Value $file.Name
        $obj | Add-Member -MemberType NoteProperty -Name FullPath -Value $file.FullName
        $obj | Add-Member -MemberType NoteProperty -Name AgeInDays -Value $time_diff_in_days
        $obj | Add-Member -MemberType NoteProperty -Name SizeInMB -Value $([Math]::Round(($file.Length / 1MB),3))
        $obj
    }
} catch {
    Write-Error "Error occurred. $_"
}

Example

By default, the script returns a list of objects that shows the files in the given path and their age and size.

.\Get-OlderFiles.ps1 -Path c:\temp\myfiles

Like I said before, we can use filters now to get the files older than given days. Let us say we want files older than 10 days.

.\Get-OlderFiles.ps1 -Path c:\temp\myfiles | ? {$_.AgeInDays -gt 10}

You can do it for any other days you want. 10,60,102.. whatever is the number. It will return an empty output if there are no files older than the specified number. Just keep that in mind.

.\Get-OlderFiles.ps1 -Path c:\temp\myfiles | ? {$_.AgeInDays -gt 60}
.\Get-OlderFiles.ps1 -Path c:\temp\myfiles | ? {$_.AgeInDays -gt 102}

If you want to export the output to a CSV file, you can easily do it by using Export-CSV cmdlet.

.\Get-OlderFiles.ps1 -Path c:\temp\myfiles | ? {$_.AgeInDays -gt 60} | export-CSV c:\temp\myfiles.csv -NoTypeInformation

If you notice closely, the script returns the size of each file as well in MB. You can use the filters in a similar way to get files less than or greater than a given size. For example, the below command finds the files greater than 50Mb and exports the details to a CSV file.

.\Get-OlderFiles.ps1 -Path c:\temp\myfiles | ? {$_.SizeInMB -gt 50} |Export-CSV c:\temp\myfiles.csv -NoTypeInformation.

There are a good number of ways you can use this script. You can even use it to find files less than a given age. Please write it in the comments section below if you have trouble sorting it out. We respond back as soon as we can.

{ 1 comment }

PowerShell: Resolve IP address to name and export to CSV

In this article, we find out how to use PowerShell to read a list of IP addresses from a text file and resolve them to hostnames and then export to a CSV file for further reviewing.

A lot of systems like Windows Event logs, Firewall logs or IIS logs etc will store the connection information with IP addresses. Barely looking at the IP address may not give a good idea of what systems are connecting and resolving them to hostnames is much easier to process the data. The script that we are going to discuss will read a list of IP addresses from a text file, resolves them to hostnames, and finally exports them to CSV file.

We are going to use [System.Net.DNS] DotNet class for this purpose. The GetHostbyAddress() method available in this class will help us in resolving names to IP addresses.

Code

[CmdletBinding()]
param(
    [Parameter(Mandatory=$True)]
    [string[]]$IPAddress,
    [switch]$ExportToCSV
)

$outarr = @()
foreach($IP in $IPAddress) {
    $result = $null
    try {
        $Name = ([System.Net.DNS]::GetHostByAddress($IP)).HostName
        $result = "Success"

    } catch {
        $result = "Failed"
        $Name="NA"
    }

    $outarr += New-Object -TypeName PSObject -Property @{
        IPAddress = $IP
        Name = $Name
        Status = $result
    } | Select-Object IPAddress, Name, Status
}

if($ExportToCSV) {
    $outarr | export-csv -Path "c:\temp\iptoname.csv" -NoTypeInformation
} else {
    $outarr
}

Some of the readers of my blog might ask why to use GetHostbyAddress method when Resolve-DNSName can do the task. It is simple; the .Net method works from most of the windows computers in use today, including Windows XP. Using Resolve-DNSName requires you to run from Windows8/Windows Server 2012 or above computers. However, use Resolve-DNSName where you can, because it is simply the latest and lets you query other types of records too. The .Net method lets you query A, AAA and PTR records only.

Usage

You can use this script by passing list of IP addresses to -IPAddress parameter as shown below. The Name column indicates the name the ip resolved to, and the Status column contains whether name resolution is successful or not.

.\Resolve-IpToName.ps1 -IPAddress 69.163.176.252,98.137.246.8

You can input the list of IPAddress using text file as well.

.\Resolve-IpToName.ps1 -IPAddress (get-content c:\temp\ips.txt)

By default, the script shows the output on the screen. If you want to export them to CSV, use -ExportToCSV switch.

.\Resolve-IpToName.ps1 -IPAddress (get-content c:\temp\ips.txt) -ExportToCsv

Above CSV file gets generated when you use -ExportToCSV switch.

Hope you find this article useful. Please write in the comment section if you are looking for additional functionality. We will try to make it on the best effort basis.

{ 3 comments }

PowerShell: Get random elements from an array

In this post, we will see how to use Get-Random cmdlet to get random elements or items from a list(aka array) in PowerShell. Along with that we will also see other use cases of Get-Random and find out where else we can use it.

This cmdlet is available in previous versions of PowerShell, so there is no specific version requirement for this. For the ease of demonstration, I will use an array of numbers from 1 to 10 and use Get-Random cmdlet to display a random number out of it.

@(1,2,3,4,5,6,7,8,9,10) | Get-Random

In the above example, the list can be anything. I mean it can be a list of strings, numbers or any other items. Look at the below example to understand it better.

$services = Get-Service
$services | Get-Random

This will display a service randomly from the array of service objects. So, it is very clear that the input list can be an array of any kind of object. For the sake of further exploration, I will limit this to numbers only as some of the arguments works with numbers only.

Let us say if you need to get a random number below 100 in your scripts, do you need to generate an array first that contains numbers from 1 to 100 first? No, you don’t need to do that. You can use -Maximum parameter for this purpose.

Get-Random -Maximum 100

You can use -Minimum Parameter to specify if your range doesn’t start from 1. The below command generates a random number between 50 and 100.

Get-Random -Minimum 50 -Maximum 100

What if I am no longer interested in generating a single random number but I need 3 random numbers from the given range. The -Count parameter is very helpful in such scenarios.

1..100 | Get-Random -Count 3

The above command displays 3 random numbers between 1 and 100. However, there is a limitation here. You can not use -Maximum & -Minimum parameters with -Count parameter. I wonder why Microsoft placed such limitation. Anyways, it is the way it is.

So far we have seen several ways you can use Get-Random cmdlet for random numbers generation. Before I conclude, I want to share another tip that helps you to display all elements in array but with their order changed. This is useful if you want to shuffle the items in an array.

1..10 | Get-Random -Count 10

Have you noticed that the number we provided to the Count parameter is the size of the input? It can be size of the input array or more than that.

Hope this article is helpful. Let me know if you have any questions or more innovative ways of using Get-Random cmdlet.

{ 1 comment }

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.

{ 1 comment }

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.

{ 1 comment }

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.

{ 2 comments }

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…

{ 3 comments }