Hey, Scripting Guy! How Can I Use the Test-Path Cmdlet to Check for Resources?

Hey, Scripting Guy! How Can I Use the Test-Path Cmdlet to Check for Resources?

  • Comments 3
  • Likes

Bookmark and Share

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! Ignoring errors or bubbling up errors to the user of a script seems a bit inefficient. I mean, wouldn’t it be better to avoid the errors in the first place? I am only a beginner when it comes to writing scripts, and maybe I just do not get it, but why can’t you just write code that does not generate errors?

-- KE

 

Hey, Scripting Guy! AnswerHello KE,

Microsoft Scripting Guy Ed Wilson here. One of the bad things about having a day filled with meetings is that it really disturbs one’s schedule, disrupts one’s rhythm, and derails the ebb and flow. Not that meetings are necessarily a bad thing, but there is a cost that must be factored into the equation—a cost not just measured in labor for meeting attendance. After all, there is meeting prep work, meeting follow-up work, and then the mental context switching that occurs when shifting from one task to a meeting and then back to the task. After spending most of yesterday in meetings, my workspace feels foreign, my Zune HD seems neglected, and my teapot is missing. To ease back into normal work mode, I thought I would catch up on some of the e-mail sent to scripter@microsoft.com.

KE, you are correct. Preventing errors is much more efficient than trapping errors. At times, this is relatively easy to do; on other occasions, it can be problematic to implement. There are a number of occasions when a few simple checks will improve the reliability of your script.

One of my favorite cmdlets is Test-Path. I use it before file and registry operations. In the Windows PowerShell shell, you can use the Test-Path cmdlet to see if a file exists. The cmdlet returns a Boolean value, and true means the file exists. It will return false if the file does not exist. This is shown here:

PS C:\> test-path -Path c:\fso\test.txt
True
PS C:\>

If I am developing a script that will write to the test.txt file in the C:\fso folder, I have a number of choices that I must make before getting too far in the process. The simplest solution is to delete the file if it exists, and create a new one. However, that may not be an acceptable solution. You may want to append to the file, or you may want to create a new file with a similar name. The “correct” solution is up to you, but it all hinges on detecting the existence of the file. This is where the Test-Path comes into play.

Because the first task is to see if the file exists or not, use an if statement. In reality, we only need to know if the file does not exist. If it does not exist, we can create it. Because the Test-Path cmdlet returns true or false if the file exists, and we want to know if the file does not exist, we use the not operator to reverse the logic. This is shown here:

if(!(Test-Path -Path $path))

If the file does not exist, create it by using the New-Item cmdlet. This is shown here:

new-item -Path $path -Value "new file" –itemtype file

If the file does exist, it will trigger the Else clause. This is where we have to decide what we want to do if the file exists. In this example, we append to the text file by using the Add-Content cmdlet. This is shown here:

Add-Content -Path $path -Value "`r`n Additional content"

CheckForFileAndAddContent.ps1

$path = "c:\fso\test.txt"
if(!(Test-Path -Path $path))
  {
   new-item -Path $path -Value "new file" –itemtype file
  }
else
  {
   Add-Content -Path $path -Value "`r`n Additional content"
  }

Each time the script runs, the words “Additional content” are added to the bottom of the Test.txt file. This is shown in the following image.

Image of words "Additional content" added to end of Test.txt

 

Use the same technique when working with the registry. As seen in the CheckForRegistryKeyAndUpdate.ps1, you do not have to use the exclamation point (!) for the not operator. You can simply use –not if you wish. It makes the script more readable, but in general, I do not use it because of the extra typing that is involved. When working with the registry, it is important to remember that the Test-Path cmdlet will not report correctly on a registry entry (registry key property); it always reports false. It does, however, correctly report on the registry keys themselves. The snippet is shown here (compare these paths with those seen in the next image in this post):

PS C:\> Test-Path -Path HKCU:\Software\ScriptingGuys\Test\update
False
PS C:\> Test-Path -Path HKCU:\Software\ScriptingGuys\Test
True
PS C:\>

Use the Test-Path cmdlet to check the path to the registry key, and if it does not exist, create both the registry key and the registry key property. This is seen here:

If(-not(Test-Path -Path $path))
  {
   New-Item -Path $path -Force
   New-ItemProperty -Path $path -Name Update -Value "Updated"
  }

If the registry key does exist, we cannot determine if the registry key property exists; therefore, we use the Set-ItemProperty cmdlet. This will create the registry key property or update the key if it exists, which for our purpose is sufficient. This command is shown here:

Set-ItemProperty -Path $path -Name Update -Value "New Update"


The completed CheckForRegistryKeyAndUpdate.ps1 script is seen here.

CheckForRegistryKeyAndUpdate.ps1

$path = "HKCU:\Software\ScriptingGuys\Test"
If(-not(Test-Path -Path $path))
  {
   New-Item -Path $path -Force
   New-ItemProperty -Path $path -Name Update -Value "Updated"
  }
Else
  {
   Set-ItemProperty -Path $path -Name Update -Value "New Update"
  }

When the script runs, the registry entries shown in the following image appear.

Image of registry entries shown when script runs

 

The cool thing about the Test-Path cmdlet is that it works with other Windows PowerShell providers. For example, before creating a new alias, you may wish to use the Test-Path cmdlet to see if the alias exists. This is shown here:

PS C:\> Test-Path -Path alias:\gc
True
PS C:\>

You could use this in a script as seen in CheckForAliasAndCreate.ps1. You can see that the process works in a similar manner as the other scripts we have created today.

CheckForAliasAndCreate.ps1

$path = "Alias:\gc"
if(!(Test-Path -Path $path))
  {
   New-Alias -Name gc -Value Get-Credential
  }
else
  {
   "Alias $path already exists"
  }


If you wish to check on the existence of a function, use the function drive with the Test-Path cmdlet as shown here:

PS C:\> Test-Path -Path Function:\TabExpansion

True

PS C:\>

You can use the Test-Path cmdlet to check for variables, by inspecting the variable drive. This is shown here:

PS C:\> Test-Path -Path Variable:\PSBoundParameters

True

PS C:\>

This also works for the environmental drive, as shown here:

PS C:\> Test-Path -Path Env:\ALLUSERSPROFILE

True

PS C:\>

If you need to know if a user has a particular certificate in the certificate store, use the certificate drive as shown here:

PS C:\> Test-Path -Path cert:\CurrentUser\AuthRoot\C31EB1E720E33C8102BADC37D44DE5D4674752A8

True

PS C:\>

As you can see, using the Test-Path cmdlet with the certificate drive can pose some challenges, because you have to use the thumbprint of the certificate.

 

KE, that is all there is to using the Test-Path cmdlet to check for resources before taking action. Error Handling Week will continue tomorrow when we will talk about…wait a minute.

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Ed, it seems to not work using the Set-ItemProperty command when you want something like a DWORD. You need New-ItemProperty to enable use of the "-PropertyType" option. In the case of a DWORD value I still need to be able to check the Key Property itself and not just find the Key and then set it as you explained.

    Do you have a good way to do this? I am hacking it together, but looking for a nice way to do it.

  • How would you search to see if BOTH files exist? for instance if you only wanted to send and email when both files are present?