• 21 Nov 2017

    Minimalistic Error Handling

    Error handling does not necessarily have to be complex. It can be as simple as checking whether the last command executed successfully: # suppress errors by default $ErrorActionPreference = ' SilentlyContinue ' # if a command runs into an error... Get-Process -Name zumsel # ...then $? is $false, and you can exit PowerShell # with a return value, i.e. 55 if ( ! $? ) { exit 55 } PowerShell reports back in...
    • 20 Nov 2017

    Temporarily Disabling PSReadLine Module

    Beginning in PowerShell 5, the PowerShell console features colorized text, and there is a wealth of other new features provided by a module named PSReadLine. If you upgraded from an older PowerShell version to PowerShell 5 and are missing the colorized text, you may want to download and install PSReadLine from the PSGallery: PS C:\> Install-Module -Name PSReadLine -Scope CurrentUser Likewise, if your PS5+ console...
    • 17 Nov 2017

    Using Windows EventLog for Script Logging

    Using the built-in Windows event log architecture for script logging is great, and very simple. Here are the initial steps to prepare logging (requires Administrator privileges): #requires -runasadministrator New-EventLog -LogName PSScriptLog -Source Logon , Installation , Misc , Secret Limit-EventLog -LogName PSScriptLog -MaximumSize 10 MB -OverflowAction OverwriteAsNeeded You may want to adjust the log name...
    • 16 Nov 2017

    Getting File Extension

    By converting a path to a FileInfo object, you can easily determine the path parent folder or file extension. Have a look: ([ IO.FileInfo ] ' c:\test\abc.ps1 ' ) . Extension ([ IO.FileInfo ] ' c:\test\abc.ps1 ' ) . DirectoryName ReTweet this Tip!
    • 15 Nov 2017

    Working with [FileInfo] Object

    Often, code needs to check on files, and for example test whether the file exists or exceeds a given size. Here is some commonly used code: $logFile = " $PSScriptRoot\mylog.txt " $exists = Test-Path -Path $logFile if ( $exists ) { $data = Get-Item -Path $logFile if ( $data . Length -gt 100 KB ) { Remove-Item -Path $logFile } } By immediately converting a string path into a FileInfo object, you can...
    • 14 Nov 2017

    Script Logging Made Easy

    Beginning in PowerShell 5, you can use Start-Transcript in any host to log all the output created by your script. Here is how you can easily add logging capabilities to any script: # add this: ############################ $logFile = " $PSScriptRoot\mylog.txt " Start-Transcript -Path $logFile -Append ######################################### "Hello" ( $a = Get-Service ) "I received $($a.Count) services....
    • 13 Nov 2017

    Multi-Language Voice Output

    On Windows 10, the operating system ships with a bunch of high-quality text-to-speech engines and is no longer limited to just the English language. The number of available TTS Engines depends on the languages you installed. PowerShell can send text to these TTS Engines, and via tags can also control the language used. If you have both the English and German TTS Engines installed, you could mix languages like below...
    • 10 Nov 2017

    Removing Text from Strings

    Occasionally, you might read about Trim(), TrimStart(), and TrimEnd() to remove text from strings. And this seems to really work well: PS C:\> $testvalue = "this is strange" PS C:\> $testvalue.TrimEnd("strange") this is PS C:\> But what about this? PS C:\> $testvalue = "this is strange" PS C:\> $testvalue.TrimEnd(" strange") this i PS C:\> The truth is that Trim() methods treat your argument as a list...
    • 9 Nov 2017

    Uncompressing Serialized Data

    In the previous tip you learned how you can use Export-CliXml to serialize data and then use Compress-Archive to shrink the huge XML files to only a fraction of original size. Today, we do the opposite: we take a ZIP file that contains XML serialization data, and restore (“rehydrate”) the serialized objects. This of course assumes you created such a file with yesterday’s tip. # path to existing ZIP file $ZipPath...
    • 8 Nov 2017

    Compressing Serialized Data

    With Export-CliXml, it is trivial to serialize results to a file, and with Import-CliXml, the serialized information can just as easily be restored. However, the resulting XML files can become rather large. Fortunately, in PowerShell 5 there is a new cmdlet called Compress-Archive. After you created the XML file, you could automatically refactor it into a ZIP file. Here is some code to illustrate: it gets a process...
    • 7 Nov 2017

    Multipass: Securely Storing Multiple Credentials

    If you’d like to safely store credentials (usernames and password) for your personal use in a file, here is a very simple yet extremely powerful approach. Take a look at this code: $Path = " $home\Desktop\multipass.xml " [ PSCustomObject ] @ { User1 = Get-Credential -Message User1 User2 = Get-Credential -Message User2 User3 = Get-Credential -Message User3 } | Export-Clixml -Path $Path When you run it, it...
    • 6 Nov 2017

    A Better (and Faster) Start-Job

    Start-Job transfers a script block to a new PowerShell process so that it can run separately and in parallel. Here is a very simple sample illustrating the idea behind jobs: # three separate "jobs" to do: $job1 = { Start-Sleep -Seconds 6 ; 1 } $job2 = { Start-Sleep -Seconds 8 ; 2 } $job3 = { Start-Sleep -Seconds 5 ; 3 } # execute two of them in background jobs $j1 = Start-Job -ScriptBlock $job1 $j3 = Start...
    • 3 Nov 2017

    Using Digital Signatures with Timestamp Server

    When you start signing script files, you want to make sure signatures stay intact even if the certificate that signed it expires at some day in the future. What matters is that the certificate was valid when it signed the script. To ensure this, you need a timestamp server from a trusted authority that adds a timestamp to the signature. This way, you not only signed a script. You also added the date when you signed...
    • 2 Nov 2017

    Digitally Signing PowerShell Scripts

    In the previous tips you learned how you can create a self-signed code signing certificate, save it to a PFX file, and read it back into memory. Today, assuming that you have a PFX file with a code signing certificate by now, we’ll look at how PowerShell scripts can be digitally signed. The below code searches for all PowerShell scripts in your user profile, and if the scripts do not have a digital signature yet...
    • 1 Nov 2017

    Loading Certificates from PFX Files

    In the previous tip we illustrated how you can use New-SelfSignedCertificate to create new code signing certificates, and store them as a PFX file. Let’s check out today how you can load a PFX file. Let’s assume your PFX file is located in $env:temp\codeSignCert.pfx. Then this is the code you need to read the file: $cert = Get-PfxCertificate -FilePath " $env:temp\codeSignCert.pfx " When you do this, you will...
    • 31 Oct 2017

    Creating Self-Signed Code Signing Certificates

    If you’d like to digitally sign your scripts, the first thing you need is a digital certificate with the designated purpose set to “Code Signing”. To play, you can easily create your own free self-signed certificates. Don’t expect anyone else to trust them, as anyone can create them. They are a great way to test-drive code signing. Beginning in PowerShell 4, the cmdlet New-SelfSignedCertificate can create code signing...
    • 30 Oct 2017

    Using LDAP Filters in Active Directory

    LDAP filters resemble the query language used by Active Directory, and if you have installed Microsoft’s RSAT tools, you can easily use the cmdlets found in the ActiveDirectory module to use LDAP filters to search for users, computers, or other resources. This would find all users with no email address: $filter = ' (&(objectCategory=person)(objectClass=user)(!mail=*)) ' Get-ADUser -LDAPFilter $filter -Prop * ...
    • 27 Oct 2017

    Comparing Computer Data Received from PowerShell Remoting

    PowerShell remoting is a very fast way to query multiple computers because PowerShell remoting works in parallel. Here is a real world use case that illustrates a couple of interesting techniques. The goal is to retrieve the list of running processes from two computers, then find the differences. For maximum speed, the process lists are queried via PowerShell remoting and Invoke-Command and results are received from...
    • 26 Oct 2017

    Generating MD5 Hashes from Text

    The Get-FileHash cmdlet can generate hash codes for file content. It cannot generate hash codes for arbitrary text, though. And it is available only in PowerShell 5 and better. So here is a small function that uses the .NET Framework to generate MD5 hashes from any text: Function Get-StringHash { param ( [ String ] $String , $HashName = "MD5" ) $bytes = [ System.Text.Encoding ] :: UTF8 . GetBytes ( $String...
    • 25 Oct 2017

    Finding File Duplicates

    In the previous tip we explained how the Get-FileHash cmdlet (new in PowerShell 5) can generate the unique MD5 hash for script files. Hashes can be easily used to find duplicate files. In essence, a hash table is used to check whether the file hash was discovered before. The code below examines all script files in your user profile and reports duplicate files: $dict = @ {} Get-ChildItem -Path $home -Filter * ....
    • 24 Oct 2017

    Creating MD5 File Hashes

    MD5 file hashes uniquely identify file content and can be used to check whether file content is identical. In PowerShell 5, there is a new cmdlet that creates the hashes for you. The code below looks for all PowerShell scripts in your user profile, and generates MD5 hashes for each file: Get-ChildItem -Path $home -Filter * . ps1 -Recurse | Get-FileHash -Algorithm MD5 | Select-Object -ExpandProperty Hash A better...
    • 23 Oct 2017

    Creating Balloon Tips Safely

    Inspired by an article by fellow MVP Boe Prox, below you’ll find a sophisticated function that creates balloon tip dialogs. You can find background information about the concepts in Boe’s original article: https://mcpmag.com/articles/2017/09/07/creating-a-balloon-tip-notification-using-powershell.aspx . You can find many tips showing how to display a balloon tip, but most of these approaches leave behind a non-functional...
    • 20 Oct 2017

    Creating Leading Zeros

    Did you ever need to convert numbers into strings with leading zeros, for example to compose server names? Simply use PowerShell’s “-f” operator: $id = 12 ' server{0:d4} ' -f $id Here is the output: server0012 The –f operator expects a text template on its left side, and value(s) on its right side. Inside the text template, use {x} as placeholder(s) for your values on the right side. Placeholders start...
    • 19 Oct 2017

    Demystifying Error Handling

    Any error in PowerShell code surfaces as an error record object. Check out the function below which extracts all relevant error information from such error record: function Get-ErrorInfo { param ( [ Parameter ( ValueFrompipeline )] [ Management.Automation.ErrorRecord ] $errorRecord ) process { $info = [ PSCustomObject ] @ { Exception = $errorRecord . Exception . Message Reason = $errorRecord . CategoryInfo...
    • 18 Oct 2017

    Determine Boot Time and Uptime Remotely

    Get-CimInstance is a useful cmdlet to retrieve WMI information because it uses standard .NET DateTime objects rather than the awkward WMI datetime format. However, Get-CimInstance uses WinRM for remote access whereas the older Get-WmiObject used DCOM for remote access. Very old systems may not yet be configured to use WinRM remoting, and may still require DCOM. Here is sample code that illustrates how you can use Get...