Skip to the main content.

ScriptRunner Blog

5 PowerShell best practices – How to work even more efficiently with PowerShell

Table of contents

 

 

Post Featured Image

The effectiveness of any tool depends on the methods used this also applies to PowerShell. This article presents five best practices for everyday admin work. 

A very good script is characterized not only by achieving a desired result, but also by its reliability, portability and traceability. This article is a continuation of 'Best Practices – from executable to professional code' and takes a look at five best practices to follow to get the most out of PowerShell and write scripts that not only work, but can survive and be customized in different scenarios.

 

Idempotency: Ensure that your scripts are executed repeatedly and safely  

Consistency is crucial, especially when automating repetitive tasks: The principle of idempotency plays an important role here. An idempotent script or function ensures that you can execute it several times and get the same result each time without generating unwanted side effects.

Imagine a script that is supposed to create a file on a server. An idempotent script would first check whether the file already existed. If so, it would do nothing or update the file. However, it would certainly not create a second file with the same name or display an error message.

If you pay attention to idempotency in PowerShell, this means:

  • Check the current state before making any changes.
  • Avoid actions that could have different results or unintended side effects if executed repeatedly.
  • Use cmdlets that are idempotent, such as Set-* instead of Add-*, if you want to ensure that a resource is in a certain state.

By ensuring that your scripts are idempotent, you not only minimize errors, but also enable safer automation scenarios where scripts may be executed regularly or automatically.

As an example, you want to make sure that a directory exists before you create a file in it:


$directoryPath = "C:\ExampleDirectory"
if (-not (Test-Path $directoryPath)) {
    New-Item -Path $directoryPath -ItemType Directory
} else {
    Write-Output "The directory already exists."
}

By integrating these checks into your PowerShell scripts, you ensure consistent execution, regardless of how often the script is executed.

 

Error handling: Consistently use try-catch-finally 

Error handling plays a central role in any script or program. In PowerShell, the try-catch-finally construct provides you with a robust method for reacting to errors. This ensures that clean-up work is carried out consistently.

  • Try: This block contains the code that could potentially cause errors. If an error occurs in the try block and this has an aborting character (e.g. through the ErrorAction Stop parameter), the execution is passed directly to the associated catch block.
  • Catch: This part becomes active as soon as an error occurs in the try block. Here you have the option of handling the error – for example by logging or notifications.
  • Finally: This section is always executed, regardless of the result of the try block. It is used for clean-up work or other final actions.

A common procedure is to create temporary files during execution, which should then be removed again, as shown below:



$tempFile = "C:\Temp\myTempFile.txt"

try {
    # Create temporary file
    New-Item -Path $tempFile -ItemType File -Force

    # Do things with the temporary file
    # ...
}
catch {
    Write-Output "An error occurred: $_"
}
finally {
    # Ensure that the temporary file is deleted in the end
    if (Test-Path $tempFile) {
        Remove-Item -Path $tempFile -Force
        Write-Output "Temporary file has been removed."
    }
}

 

Integrating this error handling construct into your scripts ensures that you are prepared for potential errors and that you are able to address them adequately.

 

Minimize dependencies: Write portable scripts

It is often necessary for scripts to be able to run on different systems. One of the main goals should therefore be to make scripts as portable as possible. This means minimizing dependencies and ensuring that the script works consistently under different conditions. Minimizing dependencies prevents scripts from not working in certain environments because a specific resource or tool is missing. The less specific requirements are placed on a script, the more likely it is to work smoothly on a variety of systems.

A common scenario in PowerShell is the use of external tools or programs. However, PowerShell often provides built-in cmdlets that can serve the same purpose, and using these cmdlets can help reduce dependencies. Instead of relying on external programs like systeminfo.exe, which may be missing on some systems or provide different output, you can rely on built-in PowerShell cmdlets.


# Not recommended: Using an external program
$output = & "systeminfo.exe"

# Recommended: Using a built-in PowerShell cmdlet
$systemInfo = Get-CimInstance -ClassName Win32_OperatingSystem

 

  • In the first example, the external program systeminfo.exe is used to collect information about the operating system. While this program is present on many Windows systems, its output may vary depending on the version or configuration.
  • The second example uses the Get-CimInstance cmdlet with the Win32_OperatingSystem class to get detailed information about the operating system. Since this cmdlet is directly integrated into PowerShell and retrieves standardized CIM information, the output is more consistent and the script has fewer external dependencies.

 

 

Additional tips:

  • Avoid fixed paths: Instead of using fixed paths in your script, consider using relative paths or parameters.
  • Prüfe auf Vorhandensein von Ressourcen: Bevor du auf eine bestimmte Ressource zugreifst, überprüfe, ob sie tatsächlich vorhanden ist (z. B. mit Test-Path).
  • Check for the presence of resources: Before accessing a specific resource, check whether it actually exists (e.g. with Test-Path).
  • Document dependencies: If your script does require external tools or specific resources, document these dependencies at the beginning of your script.

 

Minimizing dependencies in PowerShell scripts ensures that they work consistently and reliably on a larger number of systems and in different environments.

 

Avoid interactive dialogs: Focus on automation!  

Interactive dialogs can be useful if you work with them directly. But in automated IT environments, they can become a problem. If a dialog appears while a script is running, human interaction becomes necessary. This interrupts the automation flow and increases the potential for errors.

Imagine a scenario in which a script is supposed to query information from a server. Instead of asking you for the server name at runtime, the script should accept it as a parameter.


# Not recommended: Query server name interactively
$serverName = Read-Host "Please enter the server name."
$serverInfo = Get-ADComputer -Identity $serverName

# Recommended: Accept server name as parameter
param($serverName)
$serverInfo = Get-ADComputer -Identity $serverName

 

  • In the first example, Read-Host is used to ask you for the server name at runtime. This is not ideal for automated environments as it involves you/human interaction in the process.
  • In the second example, the script takes the server name as a parameter. This allows the script to run automatically for different server names without you having to intervene.

Using parameters not only promotes automation, but also the reusability of the script in different contexts.

 

Consistent logging practices: Always keep on top of things   

In complex IT environments, it is essential to have accurate records of the actions and results of scripts and automation tools. Consistent and detailed logging allows administrators to quickly identify, diagnose and resolve issues. In addition, good logs provide a way to track execution history, which can be very useful when troubleshooting or analyzing incidents.

The Write-Host cmdlet outputs information directly to the console and should be avoided in production environments. A more structured and production-ready method would be to use a dedicated logging function such as Write-Log


# Define the Write-Log function

function Write-Log {
    param 
    (
      [Parameter(Mandatory=$true)]
      [string]$Message,
      [Parameter(Mandatory=$false)]
      [string]$LogPath = "C:\Logs\MyScript.log"
    )
    Add-Content -Path $LogPath -Value "$(Get-Date) - $Message"
}

# Not recommended: Use Write-Host for direct console output
Write-Host "This action has been completed."

# Recommended: Use Write-Log for consistent logging practices
Write-Log -Message "This action has been completed."

 

  • In the non-recommended example, the script uses Write-Host to output a message directly to the console. While this can be useful in development environments, it is not ideal for production environments as such messages are not logged and are not available for later analysis.
  • The recommended example defines a Write-Log function that saves each message with a timestamp in a log file. This ensures that all activities and results are recorded for later review and analysis.

 

A few more tips:


  • Log-Rotation: Consider how to keep the size of log files under control so that they don't grow too large and consume excessive resources.
  • Centralized Logging: You may want to use centralized logging tools such as the ELK Stack or Graylog to collect and analyze logs centrally.
  • Don't re-engineer everything: There are already many modules that make logging in PowerShell easier. My recommendation here is the PSFramework module by Friedrich Weinmann (here on GitHub). 

 

Conclusion

PowerShell offers numerous options for automating and managing IT environments. However, as with any tool, the key to success lies in using it correctly. Anyone working with PowerShell should consider these best practices to create robust, reliable and sustainable solutions.

 

Good2know

Your ultimate PowerShell Cheat Sheet

Unleash the full potential of PowerShell with our handy poster. Whether you're a beginner or a seasoned pro, this cheat sheet is designed to be your go-to resource for the most important and commonly used cmdlets.

The poster is available for download and in paper form.

PowerShell Poster 2023

 

Get your poster here!

 

 

 

Related links

Related posts

5 min read

Mastering PowerShell with Get-Help

9 min read

Top ten tasks for Microsoft Purview PowerShell

10 min read

Pipeline-Ready: Advanced PowerShell functions

About the author: