Category Archives: PowerShell

How to Quickly Find Hyperlinks in Excel using PowerShell

I recently had the requirement to fetch out all of the hyperlinks from a Large excel worksheet to prepare another document and its repetitive monthly task. While I could have gone the manual approach by looking through all of the cells in the worksheet and fetching/copying all of the hyperlinks through manually, that would have been a long grueling thing to perform. So we thought to create an Automated script to perform this action instead of Manual work,

For this scenario, we have the PowerShell COM object creation to hook into Excel. Application COM object and then open up an existing Excel document and locate all of the hyperlinks which are in the spreadsheet. Automation will always be better than manual if allowed to use it. Instead of giving a deep conversation, let us start implementation quickly.

STEP #1: Create Excel.Application COM Object

The first thing that you need to do is to create Excel.Application COM object.

$excel = New-Object -ComObject excel.application
$excel.visible = $False

STEP #2: Open the excel using the Open method

Now you can open up the existing Excel document using the Open method under the Workbooks property on the Excel object. Note that you need to supply the full path of the document else it will throw the error. Here I take a sample sheet with a dummy value (shown in the below snapshot)

$workbook = $excel.Workbooks.Open(‘C:\dotnet-helpers\MyExcel.xlsx’)

STEP #3: Fetch the Hyperlinks using a worksheet object which has a property called Hyperlinks

In this article, based on my requirement here I am using many worksheets so I will Loop the WorkSheet to validate the sheet one by one. If you have only a single worksheet, you can use the WorkSheet property and specify ‘1’ which says to use the first worksheet in the workbook. If you wanted the second worksheet, you would have used a ‘2’ as an increment way.

The worksheet object has a property called Hyperlinks which lists all of the cells which have hyperlinks. As per the below code, not only do you get the hyperlinks, but also the display text, cell Ranges, etc.,

#Looping the Sheets to check all the sheets in the Excel
for ($loop_index = 1; $loop_index -le $workbook.Sheets.Count; $loop_index++)
{
         #Assigining the hyperlinks to the Variable from each sheet
         $Sheet = $workbook.Worksheets($loop_index).Hyperlinks
        #looping the Sheet one by one and store it in collection
        $Sheet | ForEach-Object
                 {
                 $Range = $_.Range
                 [pscustomobject]@{
                 SheetName = $workbook.Worksheets($loop_index).name
                LinkText = $_.TextToDisplay
               Url = $_.Address
               Cell = $Range.Row , $Range.Column
                                                  }
              }
}

STEP #3: Finally kill the Excel process

The below cmdlet will kill all the open excel in the specific system. In my server, we will not open any excel so I am confident to use this in my automation. So you ensure before using this below line of code.

Stop-Process -name excel

Final Code

####################################################
#Project : Fetch all the Hyperlinks from the excel 
#Developer : Thiyagu S (dotnet-helpers.com) 
#Tools : PowerShell 5.1.15063.1155 
#E-Mail : mail2thiyaguji@gmail.com 
####################################################

#Load Excel
$excel = New-Object -ComObject excel.application
$excel.visible = $False
$workbook = $excel.Workbooks.Open('C:\dotnet-helpers\MyExcel.xlsx')

#Looping the Workbook sheet to check all the sheets in the Excel
for ($loop_index = 1; $loop_index -le $workbook.Sheets.Count; $loop_index++)
{
#Assigining the hyperlinks to the Variable from each sheet
$Sheet = $workbook.Worksheets($loop_index).Hyperlinks
#looping the Sheet one by one and store it in collection
$Sheet | ForEach-Object 
    {
    $Range = $_.Range
    [pscustomobject]@{
        SheetName = $workbook.Worksheets($loop_index).name
        LinkText = $_.TextToDisplay
        Url = $_.Address
        Cell = $Range.Row , $Range.Column 
       
                     }
    }
}
#Kill the excel
Stop-Process -name excel

Output

How to call REST APIs using Powershell

What is API?

The API is not the database or even the server, it is the code that governs the access point(s) for the server. APIs allow developers to interact with online services without actually having to point and click their way through a UI.

Where we can have this scenario?

You can use REST APIs to manage GitHub, Azure, work with Microsoft 365, or use cognitive services in Azure.  Still, we have a lot of other use cases. In this post, we will explain with a very simple guide on how you can make REST API calls from PowerShell.

How to interact with APIs through Powershell?

The two most common PowerShell methods of interacting with REST API’s are to use either Invoke-RestMethod or Invoke-WebRequest.  To interact with a REST API the best option is to use Invoke-RestMethod. Invoke-RestMethod turns input JSON or XML into native PowerShell objects to make further interaction easy. In this post, we will continue our travel with Invoke-RestMethod to access the API.

Example

Let’s start with a simple example. We’ll need an existing REST API to work. Browsing around on the Internet, I come across a Dummy REST API called dummy.restapiexample.com/api/v1/. Every REST API has a base URI and an endpoint. Our API has a base URI of http://dummy.restapiexample.com/ and has an endpoint of /API/v1/employees, making the endpoint URI http://dummy.restapiexample.com/api/v1/employees.

$GetAPI_EMPDetails = @{
“URI” = ‘http://dummy.restapiexample.com/api/v1/employees’
}
Invoke-RestMethod @GetAPI_EMPDetails

Once the above code is executed the GetAPI_EMPDetails will have the object of employee details. Post the, we can start our future manipulation based on the data which we GET from the API.

Output:

 

 

 

How to Create XML file for the current Running services using Powershell

As a System Admin, I came up with a requirement of creating an XML file for a currently running process from Multiple systems as output using PowerShell code. Post this, the same XML file will be consumed by an external trend reporting process.

The ConvertTo-Xml cmdlet creates an XML-based representation of one or more .NET objects. To use this cmdlet, pipe one or more objects to the cmdlet, or use the InputObject parameter to specify the object. We also use Export-Clixml for the same scenario, we will review this in the upcoming article.

In this article, I am going to explain with simple XML creation method using XmlWrite and here we want to get current running service information using Get-Service from each computer and save the results to an XML file.

STEP #1: Get currently Running service using the Get-Service cmdlet

$xmlString = Get-Service | Where-Object {$_.Status -eq “Running”}

STEP #2: Convert the output in the ConvertTo-XML with As parameter

Technically ConvertTo-XML is working but in its current usage, it is returning an XML document object and only showing the top two properties. 

ConvertTo-XML -as String, this command converts the process objects that represent all of the services on the computer into an XML document and finally convert as String as output

$xmlString = Get-Service | Where-Object {$_.Status -eq “Running”} | ConvertTo-XML -as String

You can use -Depth parameter, which specifies how many levels of contained objects are included in the XML representation. The default value is 1.

STEP #3: Output the String in an XML file on the specific location

$xmlString | Out-File -FilePath C:\dotnet-helpers\MyServices.xml -encoding utf8

Entire Code

################################################################################### 
#Project : How to Create XML file for the current Running services using Powershell
#Developer : Thiyagu S (dotnet-helpers.com)
#Tools : PowerShell 5.1.15063.1155 [irp]
#E-Mail: mail2thiyaguji@gmail.com 
###################################################################################

$xmlString = Get-Service | Where-Object {$_.Status -eq "Running"} | ConvertTo-XML -as String
$xmlString | Out-File -FilePath C:\dotnet-helpers\MyServices.xml -encoding utf8

Output

 

Creating a Simple XML Document using Powershell XmlWriter()

Recently, I came up with a requirement of creating an XML file as output using PowerShell code. I want to get some service information from each computer and save the results to an XML file. Post this, the XML file will be consumed by an external trend reporting process. In this article, I am going to explain with simple XML creation method using XmlWrite with some static inputs.

STEP #1: Create & Set The Formatting with XmlWriterSettings class

First, we need to get an XmlTextWriter object to create the XML and assign the Indent values as true to make the elements to be arranged in a new line. The XmlWriterSettings class provides properties that control data conformance and output format.

$xmlObjectsettings = New-Object System.Xml.XmlWriterSettings
#Indent: Gets or sets a value indicating whether to indent elements.
$xmlObjectsettings.Indent = $true
$xmlObjectsettings.IndentChars = ” “

STEP #2: Set the XML File Path and Create The Document

# Set the File path & Create The Document
$XmlFilePath = “C:\dotnet-helpers\MyXmlFile.xml”
$XmlObjectWriter = [System.XML.XmlWriter]::Create($XmlFilePath, $xmlObjectsettings)

STEP #3 : Write the XML Declaration

When WriteStartDocument is called the writer validates that what you are writing is a well-formed XML document.For example, it checks that the XML declaration is the first node, that one and only one root-level element exists, and so on. If this method is not called, the writer assumes an XML fragment is being written and applies no root level rules.

#Write the XML delcaration.
$XmlObjectWriter.WriteStartDocument()

STEP #4: Start the Root Element and build with child nodes

In this step we are going to form the HTML elments using the WriteStartElement , WriteEndElement() ,WriteElementString , WriteComment…

XmlObjectWriter.WriteComment(“writes out a start tag with the specified local name.”)
$XmlObjectWriter.WriteStartElement(“BaseSettings“) # <– BaseSettings

$XmlObjectWriter.WriteStartElement(“ConfigSettings“) # <– Start ConfigSettings
$XmlObjectWriter.WriteElementString(“India”,”200$”)
$XmlObjectWriter.WriteElementString(“UAE”,”150$”)

$XmlObjectWriter.WriteStartElement(“ChildConfigSettings“) # <– Start ChildConfigSettings
$XmlObjectWriter.WriteElementString(“UK”,”250$”)

$XmlObjectWriter.WriteEndElement() # <– End ChildConfigSettings
$XmlObjectWriter.WriteEndElement() # <– End ConfigSettings
$XmlObjectWriter.WriteEndElement() # <– End BaseSettings

STEP #5 : Finally close the XML Document

$XmlObjectWriter.WriteEndDocument()
$XmlObjectWriter.Flush()
$XmlObjectWriter.Close()

Full Code

############################################################################
#Project: Creating a Simple XML Document using XmlWriter()
#Developer: Thiyagu S (dotnet-helpers.com)
#Tools : PowerShell 5.1.15063.1155 [irp]
#E-Mail: mail2thiyaguji@gmail.com 
###########################################################################

# Create & Set The Formatting with XmlWriterSettings class
$xmlObjectsettings = New-Object System.Xml.XmlWriterSettings
#Indent: Gets or sets a value indicating whether to indent elements.
$xmlObjectsettings.Indent = $true
#Gets or sets the character string to use when indenting. This setting is used when the Indent property is set to true.
$xmlObjectsettings.IndentChars = "    "

# Set the File path & Create The Document
$XmlFilePath = "C:\dotnet-helpers\MyXmlFile.xml"
$XmlObjectWriter = [System.XML.XmlWriter]::Create($XmlFilePath, $xmlObjectsettings)

# Write the XML declaration and set the XSL
$XmlObjectWriter.WriteStartDocument()


# Start the Root Element and build with child nodes
$XmlObjectWriter.WriteComment("writes out a start tag with the specified local name.")
$XmlObjectWriter.WriteStartElement("BaseSettings") # <-- BaseSettings
  
    $XmlObjectWriter.WriteStartElement("ConfigSettings") # <-- Start ConfigSettings

        $XmlObjectWriter.WriteElementString("India","200$")
        $XmlObjectWriter.WriteElementString("UAE","150$")

        $XmlObjectWriter.WriteStartElement("ChildConfigSettings") # <-- Start ChildConfigSettings 
            $XmlObjectWriter.WriteElementString("UK","250$")
            $XmlObjectWriter.WriteEndElement() # <-- End ChildConfigSettings

    $XmlObjectWriter.WriteEndElement() # <-- End ConfigSettings

$XmlObjectWriter.WriteEndElement() # <-- End BaseSettings 

# Finally close the XML Document
$XmlObjectWriter.WriteEndDocument()
$XmlObjectWriter.Flush()
$XmlObjectWriter.Close()

Output XML File :

There are additional ways to create custom XML. and there are plenty of methods that we can experiment. We will discuss in the upcoming posts 

 

Merge/Combine JSON objects using Array in PowerShell

In which Scenario do we use JSON object?

Mostly When REST APIs return data in JSON format, you can get at it through PowerShell.So there you have it, working with JSON data can be easy once you turn it into PowerShell objects. Hopefully, this helps you work with APIs and process data on yours.

Recently I was processing some JSON files for one of my projects and wanted to merge multiple similar JSON data into a single JSON.  All the data I was processing were in a similar JSON format, however, coming from different sources. This post will discuss simple JSON data and how we can combine it with single JSON data.

You can also read Application Pool Monitoring Automation – Powershell to check if an application pool has stoppedCreating a scheduled task with PowerShell

Step #1

Declare/Get the JSON data and assigned it to the variable. To make a simple example, I had created two variables to contain the EMP details based on Countries and want to combine those data to have consolidated Employee details.

$Ind_EMPDetails = ‘{ “Indian_EMPDetails” : [ { “firstName”: “Mike”, “lastName”: “John” }, { “firstName”: “Joseph”, “lastName”: “laz” } ] }’

$UK_EMPDetails = ‘{ “UK_EMPDetails” : [ { “firstName”: “Peter”, “lastName”: “Joe” } ] }’

Step #2

Declaring the Empty array for Merging the two JSON objects (ie., $Ind_EMPDetails & $UK_EMPDetails)

$totalEMPDetails = @()

Step #3

Merge the two JSON objects using the ConvertFrom-Json cmdlet. As we are aware, Powershell can’t merge the Json object directly and we need to perform by converting it into the custom PSCustomObject object. We need to use ConvertFrom-Json cmdlet for Combining the JSON objects, ConvertFrom-Json cmdlet converts a JavaScript Object Notation (JSON) formatted string to a custom PSCustomObject object that has a property for each field in the JSON string.

$totalEMPDetails += ConvertFrom-Json $Ind_EMPDetails
$totalEMPDetails += ConvertFrom-Json $UK_EMPDetails

Step #4

After Merging, we can use ConvertTo-Json cmdlet to converting t the Array to a JSON object. Finally, print the output in JSON format.

$totalEMPDetails = $totalEMPDetails | ConvertTo-Json
$totalEMPDetails

Full Example

############################################################################
#Project: How to Combine JSON objects using Array in PowerShell
#Developer: Thiyagu S (dotnet-helpers.com)
#Tools : PowerShell 5.1.15063.1155 [irp]
#E-Mail: mail2thiyaguji@gmail.com 
###########################################################################

$totalEMPDetails = @()

$Ind_EMPDetails = '{ "Indian_EMPDetails" : [ { "firstName": "Mike", "lastName": "John" }, { "firstName": "Joseph", "lastName": "laz" } ] }'
$UK_EMPDetails = '{ "UK_EMPDetails" : [ { "firstName": "Peter", "lastName": "Joe" } ] }'

$totalEMPDetails += ConvertFrom-Json  $Ind_EMPDetails
$totalEMPDetails += ConvertFrom-Json  $UK_EMPDetails

$totalEMPDetails = $totalEMPDetails | ConvertTo-Json
$totalEMPDetails

OUTPUT:

 

How to add values to the string array from xml using Powershell

We already discussed the reading/Writing XML file using PowerShell in previous posts. Now in this post, we will discuss how to add the value to the Array or Object from the XML using Powershell. 

PowerShell has XPath but you don’t have necessarily have to use it. Instead of XPath PowerShell provides the simplest/Easiest way to read XML files, manipulate the XML document, we use the same in the example below.

EMPdetails.xml File

<EMPLOYEE_DETAILS>
    <EMP_NAME>Max</EMP_NAME>
    <EMP_NAME>John</EMP_NAME>
    <EMP_NAME>Mike Ban</EMP_NAME>
    <EMP_NAME>Beny</EMP_NAME>
</EMPLOYEE_DETAILS>

STEP 1:

The simplest way to read an XML document in PowerShell is to typecast a variable to the type [XML]. To create this variable, you can use the Get-Content cmdlet to read all of the text in an XML document. To typecast the output of Get-Content we can simply prepend the text [xml] before the variable. This tells PowerShell that we need this variable typecasted as a System.Xml.XmlDocument type instead of the default array type that normally comes from Get-Content.

$XML1path = “C:\dotnet-helper\EMPdetails.xml”

Once you’ve executed the above cmdlet, the Get-Content cmdlet will read all the raw text from the XML document and cast the output to type System.Xml.XmlDocument, you now have a variable called $XmlDocument that contains the entire XML node tree that represents that document.

STEP 2:

Now you can declare the empty array for getting XML value.

[String[]]$str_EMP_Array = @()

STEP 3:

After the execution of STEP 1, the $XmlDocument variable will have the entire XML node tree. Now you can loop the XML elements from the parent Node. From the below code, you can loop all the child elements by pointing to the parent node.

foreach ($emp_Detail in $XmlDocument.EMPLOYEE_DETAILS.EMP_NAME)
{
[String[]]$str_EMP_Array += $emp_Detail
}

STEP 4:

Finally, print the Array data.

$str_EMP_Array

Final Code:

############################################################################
#Project : How to add values to the string Array from xml using Powershell
#Developer : Thiyagu S (dotnet-helpers.com)
#Tools : PowerShell 5.1.15063.1155 [irp]
#E-Mail: mail2thiyaguji@gmail.com 
###########################################################################

$XML1path = "C:\dotnet-helper\EMPdetails.xml"
[String[]]$str_EMP_Array = @()
[xml]$XmlDocument = get-content $XML1path
foreach ($emp_Detail in $XmlDocument.EMPLOYEE_DETAILS.EMP_NAME)
{
[String[]]$str_EMP_Array += $emp_Detail
}
$str_EMP_Array

OUTPUT:

Work with Environment Variables using Windows PowerShell – Part I

Question: Hey dotnet-helpers, I wanted to see the values of all the Environment variables in my servers/PC, How do I do this in PowerShell?

Dotnet-helpers Reply :

Windows environment variables provide information about the Windows operating system. Separated into the system and user-level scopes, default environment variables can be read and modified, and new environment variables can be also added.

PowerShell can access and manage environment variables in any of the supported operating system platforms. The PowerShell environment provider simplifies this process by making it easy to view and change the environment variables.

We access environment variables using the built-in variable called $env followed by a colon and the name of the environment variable. The $env variable can be used to access all user context environment variables.

Display all the Environmental Variables

Example 1: Get Environment Variables using dir/gci/cd

Syntax : dir env: OR gci env: OR ls env: OR cd env:

You can get the complete list of environment variables using the below cmdlets which will list out all the environment variables as shown below.

Example 2: Get Environment Variables using Get-Childitem

You can get the complete list of environment variables using the Get-Childitem cmdlet. The following command list all the local environment variables.

Get-Childitem -Path Env:* | Sort-Object Name

Dispay the specific Environment Variable

Syntax : $Env:<variable-name>

In the above syntax, the dollar sign ($) indicates a variable, and the drive name (Env:) indicates an environment variable followed by the variable name (windir).

Example 1: Get Specific Environment variable using $ENV

This script will find temporary files.

$ENV:TEMP

Example 2: Get Specific Environment variable using Get-Childitem

Instead of listing all the environment variables, you can also get the value of a specific environment variable by passing the specified variable name.

Get-Childitem Env:computername

How to Un-ZIP compressed files using PowerShell Expand-Archive cmdlet

In the previous post, we have discussed how to zip the folder/files, so here we going to discuss how to unzip files and folders archives. The process is even easier than compressing them; all you need is the source file and a destination for the data ready to unzip.

Syntax : Expand-Archive -LiteralPath <PathToZipFile> -DestinationPath <PathToDestination>

In the above command, replacing <PathToZipFile> and <PathToDestination> with the path to the files you want to Un-compress and the name and folder you want it to go to, respectively

Example :

Expand-Archive -LiteralPath C:\dotnet-helpers\Source\ExtractMe.zip -DestinationPath C:\dotnet-helpers\Destination\

The destination folder specified to extract the files into will populate with the contents of the archive. If the folder didn’t exist before unzipping, PowerShell will create the folder and place the contents into it before unzipping.

If the destination folder already exists in the destination, PowerShell will return an error when it tries to unzip the files. However, you can use -Force PowerShell to overwrite the data with the new ones using the -Force parameter.

OUTPUT

How to Remove Empty Folders/Directories recursively with PowerShell

As part of System Admin, you will have control of more servers and there may be hundreds of empty folders as junk files which may take up your hard disk. While the junk files occupy disk and it became more Junk in the servers so it became critical to maintaining the important files.

The empty folders don’t take up disk space, but to organize your data better, you may want to trim them every once in a while. If you feel to manually delete empty folders then it will need to routine and time consuming manual work. So we below PowerShell script will help you t to query and delete all empty folders and subfolders.

The following PowerShell command-line deletes empty folders, located under the specified base folder recursively.

STEP #1: Get the recursive child items

First, we need to get the child items from the source path ie., C:\dotnet-helpers\TEMP Folder

//gci alias of Get-ChildItem
gci “C:\dotnet-helpers\TEMP Folder” -r

STEP #2: Fetch all the empty folders

To filter the folders/directories available in the current context, the following property can use $_.psiscontainer. It will return a boolean, indicating whether the current object is a directory or not.

PSIsContainer retrieves an array of strongly typed FileSystemInfo objects representing files and subdirectories of the current directory. The count is not 0, it doesn’t exist at all meaning that the directory is empty or holds other empty folders

(gci “C:\dotnet-helpers\TEMP Folder” -r | ? {$_.PSIsContainer -eq $True}) | ?{$_.GetFileSystemInfos().Count -eq 0}

OUTPUT

STEP #3: Remove the collection of Empty folders.

Finally, use the remove-item cmdlet to remove all the empty folder/directories 

(gci “C:\dotnet-helpers\TEMP Folder” -r | ? {$_.PSIsContainer -eq $True}) | ?{$_.GetFileSystemInfos().Count -eq 0} | remove-item

Creating Multiple Tables in single HTML Report using Powershell

Actually System Admins do a lot stuff with Powershell Scripts. Often in Powershell you get lists where data is collected in table format. All Tech/non Tech peoples loves a nice HTML report for reviewing. Creating these type of reports in PowerShell is very easy and simple with Powershell . These type of nice HTML reports can be generate with the help ConvertTo-HTML cmdlet.  Converts Microsoft .NET Framework objects into HTML that can be displayed in a Web browser. The Powershell based Reports are easy to create  and you also can create a unique .css file to make the design for all reports identically to impress with reports.

In my previous article i had posted the article which helps to create single HTLML report. Here i going to deep drive about how to populate multiple reports in single HTML format.

Create CSS File

Here i had wrote the required CSS code for the report and placed the below code in notepad and saved with the name C:\dotnet-helpers\Logreport.css. If required you can create two separate .css file and design your reports based on your requirements. 

body {
  font-family: Monospace;
  font-size: 10pt;
}
table,td, th {
  border: 1px solid black;
}
th {
  color: #00008B;
  background-color: white;
  font-size: 12pt;
}
table {
  margin-left: 30px;
}
h2 {
  font-family: Tahoma;
  color: #6D7B8D;
}
h1 {
  color: #DC143C;
}
h5 {
  color: #c7bc07;
  font-size: 10pt;
}

In the below script, I had creating two separate variable to assign the Application and System Event logs ( $applicationLog ,$systemLog). Here you can get detail post about the Event log, so refer if required more details on it.

Then you can refer the stylesheet from an external CSS file with help of -CssUri parameter (-CssUri ‘C:\dotnet-helpers_com\Logreport.css’) and generate the HTML report in the destination location. The CSS  file will applied to the HTML element during the execution and generate the report.

#######################################################################
#Project : Creating Powershell Mulitple Reports in HTML with CSS Format
#Developer : Thiyagu S (dotnet-helpers.com)
#Tools : PowerShell 5.1.15063.1155 
#E-Mail : mail2thiyaguji@gmail.com 
######################################################################
 
$applicationLog = Get-EventLog -LogName Application -Newest 5| Select-Object -Property Source, EventID, InstanceId  
convertto-html -Title "Daily Log Report"-PreContent"<H1>Daily Event Applicaton Log Report</H1>" -PostContent "<H5><i>Copy right @ dotnet-helpers.com</i></H5>" -CSSUri "C:\dotnet-helpers_com\Logreport.css"
 
$systemLog = Get-EventLog -LogName System -Newest 5 | Select-Object -Property Source, EventID, InstanceId| 
convertto-html -Title "Daily Log Report" -PreContent "<H1>Daily Event Server Log Report</H1>" -PostContent "<H5><i>Copy right @ dotnet-helpers.com</i></H5>" -CSSUri "C:\Thiyagu Disk\Logreport.css"
 
 
ConvertTo-HTML -body "$applicationLog $systemLog"  | Set-Content "C:\dotnet-helpers_com\EventLogReport.html"

OUTPUT