They are there for you, but sometimes you forget they are there… Automatic Variables! In this blog post, I will show you some examples and why they are so helpful!

What are Automatic Variables?
As the name implies, they are created automatically and are available straight away in your PowerShell session for you to use. They contain information about the user, system, default variables, runtime variables, and PowerShell settings.
Examples
Below is a list of, at least for me, useful Automatic Variables
$?
Running this will show you the result of your last command, and it will report True if it succeeded and False if it failed. For example:
C:\Users\HarmVeenstra> Get-ChildItem -Path c:\temp Directory: C:\Temp Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 6-6-2023 23:28 Wallpaper -a--- 17-5-2023 10:01 14116 apps.csv -a--- 24-3-2023 14:39 764092 files.csv -a--- 25-4-2023 23:38 846 services.txt -a--- 25-4-2023 23:39 3975 services2.txt -a--- 3-5-2023 10:42 6578 ServicesFix-3.5.1.Log -a--- 8-5-2023 19:16 400 userslicenses.csv C:\Users\HarmVeenstra> $? True
It was True because the directory could be found. If not, it will look like this:
C:\Users\HarmVeenstra> Get-ChildItem -Path c:\tempabc Get-ChildItem: Cannot find path 'C:\tempabc' because it does not exist. C:\Users\HarmVeenstra> $? False
You can use this in scripts for error handling. For example:
C:\Users\HarmVeenstra> Get-ChildItem -Path c:\tempabc Get-ChildItem: Cannot find path 'C:\tempabc' because it does not exist. C:\Users\HarmVeenstra> if ($? -ne 'True') { >> Write-Warning ("Error occured..") >> } >> else { >> Write-Host ("Folder was found, continuing...") -ForegroundColor Green >> } WARNING: Error occured..
$Error
This variable contains an array of all errors in the current PowerShell session, and it’s an excellent way to retrieve them. For example, by not enclosing True, I made an error in the first line of the if-else statement above.
C:\Users\HarmVeenstra> $Error Errors : {At line:1 char:11 + if ($? -ne True) { + ~ You must provide a value expression following the '-ne' operator., At line:1 char:12 + if ($? -ne True) { + ~~~~ Unexpected token 'True' in expression or statement., At line:1 char:12 + if ($? -ne True) { + ~~~~ Missing closing ')' after expression in 'if' statement., At line:1 char:16 + if ($? -ne True) { + ~ Unexpected token ')' in expression or statement.} Message : At line:1 char:11 + if ($? -ne True) { + ~ You must provide a value expression following the '-ne' operator. At line:1 char:12 + if ($? -ne True) { + ~~~~ Unexpected token 'True' in expression or statement. At line:1 char:12 + if ($? -ne True) { + ~~~~ Missing closing ')' after expression in 'if' statement. At line:1 char:16 + if ($? -ne True) { + ~ Unexpected token ')' in expression or statement. ErrorRecord : At line:1 char:11 + if ($? -ne True) { + ~ You must provide a value expression following the '-ne' operator. At line:1 char:12 + if ($? -ne True) { + ~~~~ Unexpected token 'True' in expression or statement. At line:1 char:12 + if ($? -ne True) { + ~~~~ Missing closing ')' after expression in 'if' statement. At line:1 char:16 + if ($? -ne True) { + ~ Unexpected token ')' in expression or statement. WasThrownFromThrowStatement : False TargetSite : System.Collections.ObjectModel.Collection`1[System.Management.Automation.PSObject] Invoke(System.Collections.IEnumerable) Data : {} InnerException : HelpLink : Source : System.Management.Automation HResult : -2146233087 StackTrace : at System.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input) at Microsoft.PowerShell.Executor.ExecuteCommandHelper(Pipeline tempPipeline, Exception& exceptionThrown, ExecutionOptions options)
Note: If you have more error messages, you can retrieve the last one by using $error[0]
$host
This gives you information about your system. I mainly use it to display the version of PowerShell, and this looks like this:
C:\> $host Name : ConsoleHost Version : 7.3.4 InstanceId : 1f3f2dbe-9ed8-49e0-a284-577282138344 UI : System.Management.Automation.Internal.Host.InternalHostUserInterface CurrentCulture : nl-NL CurrentUICulture : en-US PrivateData : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy DebuggerEnabled : True IsRunspacePushed : False Runspace : System.Management.Automation.Runspaces.LocalRunspace
$IsLinux, $IsMacOs, $IsWindows
These three variables can be used to determine the operating system on which you are running your scripts, which is easy if you have something specific in a script that only runs on Linux. It returns True or False, for example:
C:\> $IsLinux False C:\> $IsMacOS False C:\> $IsWindows True
You could use this in a script like this on Windows and get output like this:
C:\> #Get free diskspace >> if ($IsLinux) { >> df -h >> }>> elseif ($IsWindows) { >> Get-PSDrive >> } Name Used (GB) Free (GB) Provider Root CurrentLocation ---- --------- --------- -------- ---- --------------- Alias Alias C 340,12 136,06 FileSystem C:\ Cert Certificate \ D 79,51 159,24 FileSystem D:\ Env Environment Function Function HKCU Registry HKEY_CURRENT_USER HKLM Registry HKEY_LOCAL_MACHINE Temp 340,12 136,06 FileSystem C:\Users\HarmVeenstra\AppData\Loca… Variable Variable WSMan WSMan
But on Linux, you will get output like this: (Running on my Raspberry Pi 4):
PS /home/harm> #Get free diskspace PS /home/harm> if ($IsLinux) { >> df -h >> }elseif ($IsWindows) { >> Get-PSDrive >> } Filesystem Size Used Avail Use% Mounted on /dev/root 230G 19G 201G 9% / devtmpfs 1.7G 0 1.7G 0% /dev tmpfs 1.9G 20K 1.9G 1% /dev/shm tmpfs 768M 1.2M 767M 1% /run tmpfs 5.0M 0 5.0M 0% /run/lock /dev/sda1 253M 51M 202M 20% /boot tmpfs 384M 0 384M 0% /run/user/1001
Note: This is only available in PowerShell 7
$LASTEXITCODE
This is something to check if your script, or a command in your script, exited correctly with a zero as the exit code. If it differs, 1 indicates an error so you can act accordingly on that exit code. For example, you can ping a website using a Scheduled Task. If the script exits with 0, all is well. If it exits with 1, the script has failed to execute. But if the ping didn’t work or was stopped, the exit code is -1073741510, indicating it was stopped abruptly.
For example, below, I ping powershellisfun.com 4 times, and I do the same again, but CTRL-C / Stop is during pinging:
C:\> ping powershellisfun.com Pinging powershellisfun.com [192.0.78.202] with 32 bytes of data: Reply from 192.0.78.202: bytes=32 time=10ms TTL=57 Reply from 192.0.78.202: bytes=32 time=13ms TTL=57 Reply from 192.0.78.202: bytes=32 time=14ms TTL=57 Reply from 192.0.78.202: bytes=32 time=11ms TTL=57 Ping statistics for 192.0.78.202: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 10ms, Maximum = 14ms, Average = 12ms C:\> $LASTEXITCODE 0 C:\> ping powershellisfun.com Pinging powershellisfun.com [192.0.78.202] with 32 bytes of data: Reply from 192.0.78.202: bytes=32 time=14ms TTL=57 Reply from 192.0.78.202: bytes=32 time=13ms TTL=57 Ping statistics for 192.0.78.202: Packets: Sent = 2, Received = 2, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 13ms, Maximum = 14ms, Average = 13ms Control-C C:\> $LASTEXITCODE -1073741510
In a script, that would look like:
C:\> ping powershellisfun.com >> if ($LASTEXITCODE -eq '-1073741510') { >> Write-Warning ("Error occured") >> }elseif ($LASTEXITCODE -eq '0'){ >> Write-Host ("No issues reaching powershellisfun.com") -ForegroundColor Green >> } >> Pinging powershellisfun.com [192.0.78.202] with 32 bytes of data: Reply from 192.0.78.202: bytes=32 time=10ms TTL=57 Reply from 192.0.78.202: bytes=32 time=13ms TTL=57 Reply from 192.0.78.202: bytes=32 time=12ms TTL=57 Reply from 192.0.78.202: bytes=32 time=11ms TTL=57 Ping statistics for 192.0.78.202: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 10ms, Maximum = 13ms, Average = 11ms No issues reaching powershellisfun.com
$Profile
This is something I use a lot to edit my PowerShell profile quickly. It contains the full path to the current profile:
C:\> $profile C:\Users\HarmVeenstra\OneDrive - NEXXT\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
This makes viewing it easy:
C:\> type $profile [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Import-Module Posh-Git Set-PSReadlineKeyHandler -Key Tab -Function Complete Import-Module -Name Terminal-Icons Set-PSReadLineOption -PredictionSource HistoryAndPlugin Set-PSReadLineOption -PredictionViewStyle ListView Import-Module Az.Tools.Predictor Set-PSReadLineOption -PredictionSource HistoryAndPlugin
$PSCulture
This shows the regional settings/culture of your PowerShell session:
C:\> $PSCulture nl-NL
$PSCulture shows the Name property from the Get-Culture cmdlet:
C:\> Get-Culture LCID Name DisplayName ---- ---- ----------- 1043 nl-NL Dutch (Netherlands)
$PSHome
This shows the directory that your current PowerShell session is started from:
C:\> $PSHOME C:\Program Files\PowerShell\7
$PSUICulture
This shows the language setting of the UI of the operating system:
C:\> $PSUICulture en-US
This can be used, just like $PSCulture, to use language-specific settings.
$PSVersionTable
This shows more detailed information than $Host:
C:\> $PSVersionTable Name Value ---- ----- PSVersion 7.3.4 PSEdition Core GitCommitId 7.3.4 OS Microsoft Windows 10.0.22621 Platform Win32NT PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 WSManStackVersion 3.0
$true
This variable can be used to represent True in the script, but… I use it for looping things until I press CTRL-C. Easy to monitor things by letting a cmdlet run continuously. For example:
C:\> while ($true) { >> $logcount=(Get-ChildItem -Path D:\Temp -Filter *.log).count >> Write-host ("There are {0} logs in d:\temp" -f $logcount) >> Start-Sleep -Seconds 30 >> } There are 2 logs in d:\temp There are 2 logs in d:\temp There are 3 logs in d:\temp
In this example, the script counts the number of logs and waits 30 seconds to count them again. It outputs the number of logs found on the screen. For example, this is easy if you’re monitoring a folder for changes.
More information
You can find other examples on this Microsoft Learn page.
Another one I find frequently helpful, everything that falls under $env:
Yes 😊 Doesn’t necessarily fall in the Automatic Variables, but easy profile and temp path access is where I use that one for mostly