PowerShell Beginner’s Guide – Creating Functions

In this post we will be going through creating a functions in PowerShell.

PowerShell functions are reusable code created to perform specific tasks. Functions can accept inputs (parameters), process data, and produce outputs (return data).

PowerShell functions make code readability and efficiency better and allows easier automate of tasks.

Functions can be either saved in script file (.ps1), then called as part of the script or saved as modules (.psm1) and these can then be imported using the import-module command or added to a PowerShell profile so they load each time PowerShell is launched.

First we will go through creating a basic function, this can be made up of existing PowerShell commands, standard command line or we can add .Net Name spaces and classes.

Functions

To create a new function we type function and set a name. Then a script block to contain the code that will be run. When naming a functions it can be called anything but it is a good idea to keep the same Verb-Noun that is used by other PowerShell commands.

The below example will create a new command called Check-Logfiles and when its run it will use get-childitem to look in the specific logs folder

function Check-Logfiles {

Get-ChildItem C:\temp\Logs

}
Function

This can be useful if you have a repeatable tasks as you can create a new command and instead of having to add all the parameter each time to an existing command, you can just set in the function and run each time to check logs, services or any other specific checks.

Parameters

Most PowerShell commands, such as cmdlets, functions and scripts, rely on parameters to allow users to select options or provide inputs.

Parameters can be set to either required or not required by adding mandatory.

When setting parameters we need to use a type, the most common type I use is string but there are many additional like Boolean or date.

String: This can either be hardcoded text or a variable. This can then be passed to the command in the function.

Bool: Set the script to use $True, $False, 1 or 0.

Parameters can be set to either be required or not required by adding mandatory.

The below is the update Check-Logfiles function above and replaces the path with a $path variable and a confirm parameter to run the script.

 function Check-Logfiles {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)] 
        [string]$path,
        [bool]$Confrim
    )

    Get-ChildItem $path
    }
Function with parameters

Next we an add in the Boolean to put in true or false requirement to run the script.

function Check-Logfiles {

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

        [bool]$Confrim
    )

    if($Confrim -eq "True"){
    Get-ChildItem $path
    }

    else {
        Write-Warning "Confirm not set to true"
    }
    
    }
Function with Boolean

Parameter Validation

We an add validation to parameters to set what values will be accept by the parameter. To use validation we will add ValidateSet to the parameter.

For the below example we will only be accepting two paths in the Check-Logfiles function. If a users set a path outside other than the set paths the function will fail immediately and output the reason to the PowerShell console.

function Check-Logfiles {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)] 
        [ValidateSet('C:\temp\Logs','C:\temp\Logs2')]
        [string]$path
    )

    Get-ChildItem $path
    
    }

The above are just a few examples of the different ways to use a function. Functions are great way to create reusable code / commands and give structure to your scripts. Functions should be kept a small as possible and set to do only a single task this will allow easier troubleshooting.

Multiple functions can be combined in a single script to complete more complex tasks.

PowerShell Beginner’s Guide – PowerShell Remoting

In this we will be going through PowerShell remoting (PSRemoting).

PowerShell remoting is a feature that enables administrators to manage multiple computers remotely using PowerShell commands. It allows us to execute commands, run scripts, and manage configurations on one or more remote computers from a single console.

With PSremoting, we can run administrative tasks, automate processes, and manage Windows and Linux without needing to access each machine through RDP or direct console.

PowerShell Remoting User Rights

The two local groups allows users can connect to a machines remotely using PSRemoting by default:

  • Administrators
  • Remote Management Users

If users don’t require admin rights on the machine and but they will need to remote on, they should just be added to remote management users. It always best to setup least privileges for security.

Enabling PowerShell Remoting

First we need to enable PSRemoting, if it is not enabled or the WinRM ports are blocked between the two machines. We will receive and error like the below.

PS Remoting Error

To enable PSRemoting we need to run

Enable-PSRemoting
Enable PowerShell Remoting

Once enabled we can now connect using

Enter-PSSession ComputerName
PowerShell Remote Connection

Now that we are connect we can run commands as if we had the PowerShell console open directly on the remote computer.

Running Remote Command

To exit and return back to local PowerShell console, we just need to run

Exit-PSSession
Exiting PowerShell Session

Invoke-Command

Using Enter-PSSession is good for running commands against one machine but if we want to run against multiple machines we can use Invoke-command.

When running we specify the command that will be run in the sriptblock inbetween the two curly brackets {}.

Invoke-Command -ComputerName computer1,computer2 -ScriptBlock { Command}

In the below example I am running against three machines and getting the computersystem WIM class.

PowerShell Remoting Multiple Machines

PowerShell Sessions

Another method to run multiple commands against machines is to create a PowerShell session and then re-using this initial connection.

In the below example I am connect to the three machines, checking the printer spooler service and stopping the service in the third command.

PowerShell Sessions

This has been a quick few examples of setting up and using PSRemoting. Using PSRemoting makes administration a lot easier on remote machines. .

Some security teams don’t want remoting enabled (it is enabled by default on Windows Servers OS since 2012) as they see its as a security risk, while there are risks the benefits out way the risks and there are many ways to harden and reduce security risks associated with PowerShell rather than disabling PSRemoting.

PowerShell Beginner’s Guide – Error Handling Methods

In this post we will be going through different error handling methods available in PowerShell and examples on using these.

Error handling is very usefully to learn, it allow us to write scripts that can export / write errors to a log or completed certain task if a part of the script fails.

There are also two types of errors Non-Terminating and Terminating, Non-Terminating error can cause issue when using certain error handling methods, we will cover this more when we get to the try-catch section.

PowerShell has a few different ways to handle errors gracefully:

  1. Error: When using $error, we can return error messages that are stored in the default variable.
  2. Error Action Preferences: PowerShell provides different error action preferences like Stop, Continue SilentlyContinue…, allowing how to control the behavior when an error occurs.
  3. ErrorVariable: Creates a new variable to store error messages, this can then be used later to output or logging.
  4. Try-Catch: The try block run the code specified and in the event of an error the catch block catches and handles those errors. This allows for us to control how errors are managed within the script.
  5. Finally: PowerShell includes a finally block which executes regardless of whether an error occurs or not. This is useful for performing cleanup tasks or finalizing operations, like send a log file or email .

By using these features, PowerShell allows handle errors more effectively.

$Error variable

$Error is the default variable that all errors are written to, we can call this in side a script and use the index operator [0], zero returns the latest error.

I would generally not use this method but it can be usefully for simpler scripts that we just want to export the error while the script runs.

Below are some examples of using $error.

$Error[0]
Error Variable

We can also call specific properties to export more specific error propertied. We can view the properties by using Get-Member

$Error | Get-Member
Error variable additional properties

To chose a error propriety we put dot and exception.

Error variable exception

ErrorAction Parameter

ErrorAction Allows us to specify the action PowerShell should take when an error occurs. This is done using -ErrrorAction parameter.

I would generally only use this when I need to set an error to terminate and I am using error variable and don’t want to write the error to the PowerShell console.

Below example shows setting error action to continue silently.

Get-ChildItem -Path 'C:\Folder_Does_Not_Exist' -ErrorAction SilentlyContinue
Error action

ErrorVariable

ErrorVariable is used to captures error information into a custom variable, this can then be used to output to a log file or out to the PowerShell console.

This is a good method to create multiple errors objects and write a log file that outputs errors while the script runs.

Below example we are silencing the error and then adding it to a new a variable.

Error variable
Get-ChildItem -Path 'C:\Folder_Does_Not_Exist' -ErrorVariable MyErrors

$MyErrors

Below example shows exporting to a txt file.

Error variable out to file
Get-ChildItem -Path 'C:\Folder_Does_Not_Exist' -ErrorVariable MyErrors -ErrorAction SilentlyContinue

$MyErrors.Exception | Out-File C:\temp\Logs\Error_log.txt -Append

Try-Catch-Finally

The last method we will cover is try catch method, this method allows us to catch and handle errors gracefully within a script and then specify code to run in case of an error.

Try catch is a more complex error handling method as it allow for additional code or actions to be perform that can be as simple as out putting error or running additional command that could be use to fix or alert for issues while the script is running.

When using try catch the error need to be a terminating error or the catch wont work. Get-ChildItem isn’t a terminating error, due to this we will be using -ErrorAction stop to make it terminate.

Below examples show the difference when using a terminating and non-terminating error with try catch.

Try Catch terminating vs non
try {
    Get-ChildItem -Path 'C:\Folder_Does_Not_Exist'  -ErrorAction Stop
} 
catch {
    Write-Host "An error has occorred" $Error[0].ErrorDetails"
} 

We can add finally to the try catch to run a command at the end whether or not there is an error.

This can be useful if we want the script to do something like copy the log file or send a email or notification the script has completed.

Below example will remove the log file after the script has completed.

Try Catch Finally
try {
    Get-ChildItem -Path 'C:\Folder_Does_Not_Exist' -ErrorAction Stop
} 
catch {
    Write-Host "An error has occorred" $Error[0].ErrorDetails
} Finally { 
    Remove-Item C:\temp\Logs\Error_log.txt -Verbose
}

The above methods shows the different way to handle errors in PowerShell, being able to use error handling in scripts is very useful skill to learn and helps with more complex scripts.

PowerShell Beginner’s Guide – Using IF Else Statements

In this post we will be going through using if else statements.

If else statement in PowerShell evaluates a condition and executes code if the condition is true. If the condition is false, alternative code is executed.

If else can also be nested to create more complex scripts that handle multiple conditions and execute specific code for each condition.

If else follows the below format

if (condition) {
    # code to execute if condition is true
} 
else {
    # code to execute if condition is false
}

If Statement

We will first go through using a single if statement, when using a if the part between the two () is the conditions which needs to be checked.

When using an if without an operator (eq, like, gt…..), the if will check that the variable is not empty.

The below shows the difference between the if statement when there is a value and no value.

When using an operator we can specify if the value matches then run the code.

$con = "True"
if($con -eq "True"){
    Write-Host "Con is true" -ForegroundColor Green
}

If Else

Next we will go through using if and else. Adding else is a way to executed code if none of the conditions are meet.

$con = "True"
if($con -eq "True"){
    Write-Host "Con is true" -ForegroundColor Green
}
else
{
    Write-Host "Con is false" -ForegroundColor Red
}

We can add an elseif to add another condition, there is no limit to how many can be added but it can be a bit messy if there are two many if elseif’s. Also the first condition that is meet is will stop the rest from being tested.

$con = "True"
if($con -eq "True"){
    Write-Host "Con is true" -ForegroundColor Green
}
elseif ($con -eq "False") {
    Write-Host "Con is false" -ForegroundColor Red
}
else
{
    Write-Host "Con does not meet condition" -ForegroundColor Yellow
}

If with additional operator

We can test multiple conditions by using different operator in the if statement. In the below we are using the -and operator to check that condition one is true and condition two is greater than 3

We can also use -or operator which allows for us to specify two expressions and returns true if either one of them is true.

$con1 = "True"
$con2 = "5"
if ($con1 -eq "True" -or $con2 -gt "6"){Write-Host "Condition are meet" -ForegroundColor Green}

If Null

We can also check for Null values in If statements, to check if a variable or result is null we use the $null variable.

The $null variable must be on the left side of the statement as if it not PowerShell may not

Using if statements in your PowerShell scripts creates a lot of possibilities for creating dynamic and responsive automation. They can be a bit confusing at the start but with a bit of practice and experimentation, if statements become powerful tools in your scripting.

PowerShell Beginner’s Guide – Looping through objects

In this post we will be going through the different types of loops in PowerShell.

There are a few different types of loops and we will go through each and showing examples on how to use them. Loops are very useful and will be required in most scripts.

The first we will go through is a ForEach-Object loop, this is one of the main loops I use and can be used a few different ways.

Foreach Objects

First way is to get a list of objects and then pipe to our foreach-object to go through each.

Below example will get all services, loop through the results and return each name.

Get-Service | ForEach-Object { $_.Name}
Foreach-Object

Another method for using foreach-object is to use a variable with a set of object or a command that will retrieve objects and loop through each object in the variable.

There are two short hand commands for foreach-object, % and foreach.

In the below I am getting all folders under the directory and adding them to a $folders variable and looping through each.

$folders = Get-ChildItem C:\temp\ -Directory
foreach ($folder in $folders){$folder | Select-Object Name,CreationTime}

We can also use the foreach method on the variable to loop through the objects.

I mostly use foreach in my scripts as I find it the easiest to read when I have to go back over my own scripts.

While Loops

The other type of loops is a while loop.

Do while basically mean that while a condition is true the script will then keep looping.

This can be useful if we want to run a script for a certain period of time or while a process is running.

Below will loop through till the number in the variable $i is 10 then it will run the second write host.

$i = 1;
Do {
    Write-host "is $i less then 10" -ForegroundColor Red
    $i++;
}
While ($i -lt 10)
Write-Host "is 10 or greater" -ForegroundColor Green

Next we will go through do until, the different between do while and do until is that while uses true and until uses false condition.

This could be used if we wanted to check if a certain number of files or in an install script we could wait for certain process to finish before completing the next part.

Below example I am using a do until on a folder to check how many logs are there and using a do while to create the logs.

Check logs count.

Do {

    $logs = Get-ChildItem -Path C:\temp\Logs
    Start-Sleep 5
    Write-Host "Less than 10 logs found" -ForegroundColor Green
}
Until ($logs.count -gt "10" )
Write-Host "More than 10 logs found" -ForegroundColor Red

Create logs files.

$i = 1;
Do {
    New-Item "C:\temp\Logs\Log$i.log"
    $i++;
}
While ($i -lt 10)

This has been overview of some of the different types of loops and how to use them. There are pros and cons to using each and the right one to use will really depend on what the script is being used for.

PowerShell Beginner’s Guide – Filtering Objects

In this post we will be going over filtering in PowerShell and different methods available.

Filtering should be done as close to the source command as possible, this will speed up the time it takes for the command to complete and return the data.

Depending on the command used there can be a filter parameters available, if there is no filtering we would use where-object.

Where-Object can be used to filter objects based on any property that is returned from the command.

If we need help with example or the right syntax to run the command we can use

Get-Help Where-Object

Get-Help Where-Object -Examples
Where-object help

Where-object can be used with lots of filtering parameters to return objects like Contains, eg (equal to), gt (greater than), lt (less than), like…….

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/where-object?view=powershell-7.4#parameters

Once we have the syntax worked out we can start to filter the data to returned. In the below command we will return any file that has .pdf extension and just select the name to make the results easier to read.

Get-ChildItem -Path 'C:\Program Files\' -Recurse -File | Where-Object {$_.Name -like "*.pdf"} | Select-Object Name
where-object results

Get-ChildItem has a filter parameter, this allow us to test and show the speed difference when we can.

Below is the time when running the command using where-object.

Where-object command time

When we use the -filter with Get-ChildItem we can see that the time to run went from 6 second to 2 seconds.

Get-ChildItem Filter command time

This was only a small subset of data but if we where running against thousand or hundred of thousand of files this can add up and save minutes to hours of time for data to returned.

PowerShell Beginner’s Guide – Variables, Arrays and Hash Tables

In this post we will be going through the use of variables, arrays and hash table.

Variables are object that are created temporarily in the PowerShell console or created as part of script that are removed once the console is closed. There are system variables that are part of PowerShell but we will just be covering user variables in this post.

Variables are $ sign with a name.

We can then call the variable by using the name

Variable

There are two type of quotation marks single will only display the text between the quotes. We can use these for variable that have text data.

Single Quotes Variable

With double quotation marks we can passthrough text but also passthrough a variable. If we try to add a variable without double quotes it will just write the variable name and not the text in the variable.

Double Quotes Variable

There are some instance where we need to create a subexpression using $() around the variable to pass through specific data.

In the below I want to return just the first folder. The first command return all the folder names.

The second command is using a subexpression, we are then able to return the first folder name.

Subexpression results

An array is pretty similar to a variable the only really difference is that it has multiple objects broken up by using comma’s.

Text Array

We can also use @() to create any array if there is text other than number we have to use quotes.

Number Array

We can also create a blank array, I use these when doing reports and want to output data from a script.

Blank Array

We will go more in depth on using the blank array in a future post but I mostly use them with hash tables.

Next we will go through using a hash table, these are like array but there is key / value pair.

Below we have a table where we created a name, surname and role heading and set a value for each.

Hash table

We can also use array or variables in hash tables

Hash table with array

This is where hash tables can come in hand for doing reports as we can output the results of multiple commands using a blank array and a hash table, then export the results to a CSV, text or html file.

We will cover both these in later post.

In this post we covered create variables, types of quotes and there uses, array’s and hash tables with some examples of each.

PowerShell Beginner’s Guide – Sorting and Selecting Data

In this post we are going to go through sorting, selecting and formatting object data.

To be able to get the right information back in both the PowerShell console and to output to files like txt, csv, html…, it’s import to be able to format the data correctly.

We can sort by using sort-object command, in the below example we can see that the process are sorted by process name by A to Z.

Now we can use sort-object to sort the processes by ID instead of name.

We can added -descending to sort from other way either.

There can be hidden properties that can be useful, to view these we can use the Get-Member and use member type property.

Get-Process | Get-Member -MemberType Property

We can now use the property names with select-object to return the additional properties.

Select-Object has a first and last parameters that let you skip everything but the specified number of objects.

Using the below will only return the first 20 processes.

Get-Process | Select-Object -First 20

Using calculated property in Select-Object is a good way to rename a properties or use math’s to work out a value like the size of a folder or memory used by a process.

To create a calculated property we use @{Name=”Name of property”;Expression={$_.propertyname}}.

Get-Process | Select-Object Name, CPU, @{Name="Memory";Expression={$_.WorkingSet/1KB}}

In the next post we will be going through Variables, Arrays and Hash Tables

PowerShell Beginner’s Guide – Getting Started with PowerShell

In this next series of post we will go through getting start with basic commands, more advances commands and then going through how to use these to creating more complex scripts.

First cmdlets in PowerShell are named according to a verb-noun naming (mostly, there are times when people create there own command that don’t use the verb-noun naming). This pattern is to help give an understanding of what the command does and how to search for them.

Sometimes finding the specific command you want is time consuming in PowerShell. This is where the Get-Command command can come in handy

If we want to find a command by name we can use the full name

If we don’t know what the command is we can use wildcard (*) to return all command that have a conmen name.

Below example returns all command that have network in the name.

Once we have a command we can either look up the documentation or use Get-Help to view how to use the command and examples.

To view the full help with examples on how to use.

Get-Help Get-Service -Full

To view just the examples

Get-Help Get-Service -Examples

To open the webpage for the command use -Online

Get-Help Get-Service -Online

Below is a quick overview of what each verb function should be.

VerbFunction
GetReturn values (object, properties….)
NewCreate new objects (File, object….)
SetSet object (value, properties….)
OutOutput to (Console, file…..)
StartStart service, process’s ….
StopStop service, process’s…..

To return a list service’s we can run Get-Service.

If we want to filter to only return service with specific status like running we can use where-object and the status property.

If we wanted to only return the display name and status we would pipe the result using | and then use Select-Object.

If we know there is a certain restart order for an application or a restart of a service will fix a specific issue on server or endpoint device, we could then use the name and status to start or restart the service.

To run remotely (if the command supports remote calls) we an use the ComputerName (sometimes its Server, depends on the command).

In the next post we will look at sorting, selecting and additional properties of Objects in PowerShell.

Microsoft Entra ID App Registration Certs / Client Secret HTML Report

In this post we will be going through creating a HTML report for Microsoft Entra ID App registration to export a list of expired and expiring client secrets and certificates.

I wanted to create a HTML report that would highlight cert / secrets that where expired or due to expire and make it quicker to check what is due to expire.

This report will use the existing PowerShell script I created last year to export Azure App registration details to a CSV file, just updated to use an embedded CSS style sheet to format the html output.

First I needed to create a HTML style sheet, below is the HTML code I use for the HMTL formatting.

The last step was update the rows to set each row to green, orange or red depending on the status of the cert / secret.

To run the script I will be using a certificate and app registration as this allow for better automation and certificate are recommend over client secrets for security. If you need to know how to set this up I have done a previous post on this.

.\Get-AppRegistrationdetailsHTMLv2.ps1 -CertificateThumbprint thumbprint -ClientId ClientID -TenantId TenantID -ReportExport C:\temp\Graph\ -ExpiryDate 200

Below is an example of the full export.

The table and colors can be modified just have to update the style sheet.

To download the full script use the below GitHub link.

https://github.com/TheSleepyAdmin/Scripts/blob/master/MSGraph/AppRegistration/Get-AppRegistrationdetailsHTMLv2.ps1