© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
O. HeaumeUnderstanding Microsoft Intunehttps://doi.org/10.1007/978-1-4842-8850-4_5

5. Location, Location, Location

Owen Heaume1  
(1)
West Sussex, UK
 

There may be a requirement to copy files to specific locations pre- or post-application deployment. An application may require customization through a pre-configured INI (configuration) file for example, or some supporting documentation must be copied to the user’s Documents folder, or perhaps additional corporate backgrounds must be deployed as part of a Microsoft Teams installation.

There can be many reasons why you may need to copy additional files along with the deployed application. In this chapter, you will learn where to place the files and how to reference them in the PowerShell deployment script depending on their location within the root folder structure.

Where Is This Script Running from Anyway?

If you always knew the file location your deployed script was in and the source files it referenced, it would be a fantastic thing indeed. If you knew the script was deployed to a client computer, executed from C::MyKnownDirectoryMyScript.ps1 and the referenced files were in the same directory as the script then life would be magic.

When the script is downloaded to the endpoint, it will be downloaded to C:WindowsIMECache – the folder containing the actual script and source files will be in a subfolder of IMECache that is a random GUID.

Alas, when deploying scripts using Endpoint Manager you have no idea of the random GUID subfolder containing the script and any accompanying source files essential to the deployment.

You need to discover where the script is running from, only then will you be able to reference the files for copy commands to work successfully. After all, copy commands work by copying from a known source location to a destination. How can this be achieved without knowing the source?

How We Used to Do Things

In the good old days, you would write a batch file and use %dp0 to reference the current location.

The %dp0 variable, when referenced within a Windows batch file, will expand to the drive letter and path of the batch file. This meant you would never need to know where the batch file was running from.

The task now is to find the same solution using PowerShell. In the early days of PowerShell, the solutions provided were convoluted with syntax that was hard to remember. Have a look at the following PowerShell syntax:
$MyInvocation.MyCommand.Path | Split-Path -Parent

Ugly, right? Will it work? Sure, and there is certainly a place for the $MyInvocation automatic variable1 and it is capable of so much more; however, for your deployment needs there must surely be a more elegant solution.

A Better Way

Since PowerShell version 3, there is an easier method of determining where a PowerShell script is being executed from.

The automatic variable $PSScriptRoot contains the full path of the executing script's parent directory. It doesn’t get much easier than that.

You will learn how to use this automatic variable to reference files later in this chapter, but first, there needs to be an agreed method on how the files will be structured, and that’s next.

File Placement

At a minimum, you will always have two files somewhere in a directory that will make up the deployment package you will learn how to create later in the book: the PowerShell .ps1 script that will take care of the deployment and the application that will be deployed. Beyond that, there may be additional files required as part of the deployment, and deciding where to place these files inside the directory is a matter of personal preference. The only difference will be how you reference the files within a PowerShell deployment script.

Flat-File Placement

In a flat-file placement, there is no file structure. All files, regardless of type, are placed in a single directory and Figure 5-1 demonstrates this.

A screenshot of a window with a panel on top highlights the file option. This P C is selected at the menu bar on the left. The main panel on the right lists 8 files.

Figure 5-1

Everything in a single directory

Advantages of Using a Flat-File Structure

Using this method for storing all files in a single directory can be a quick option when you are only deploying an application or have only a single file type for each file that needs deploying. (Having a single file type negates the need for filters in subsequent PowerShell code, and you will see an example of using a filter later in the book using the Copy-Item cmdlet.)

Structured File Placement

In a structured approach, you should leave the deployment script in the root directory. For every file type to be deployed, including the application itself, a subdirectory is created to contain the appropriate files.

A structured file placement would resemble something like that shown in Figure 5-2.

A snapshot of a window with a panel on top highlights the file option. This P C is selected at the menu bar on the left. The panel on the right lists 3 folders and a file.

Figure 5-2

A structured file placement

In Figure 5-2, the root directory is named Deployment1 and contains the following:
  • The PowerShell DeploymentScript.ps1 in the root

  • Subdirectory named EXE to contain the application Setup.exe

  • Subdirectory named INI to contain the INI files

  • Subdirectory named JPG for the image files

Advantages of Using a Structured Approach

Not only is a structured approach more visually appealing (imagine if there were 50 or more other files to deploy), but there are also advantages to using this method.

For example, if you are copying all files in the JPG subdirectory to a destination, you can reference the source location as JPG*.* to copy everything contained within it. This simplifies the PowerShell code as you do not need to filter out the other file types when using the Copy-Item cmdlet. (Discussed later in the book.)

Whether all files are placed in a root directory or multiple subdirectories is an entirely personal preference. Just ensure the PowerShell deployment script or template you are using is always in the root location for ease, the rest doesn’t matter.

Referencing Files

Now that some thought has been given to where to place the files, and you know how to obtain the location that the script is being executed from, ($PSScriptRoot), it is time to learn how to reference the files from the PowerShell script.

First Things First

Whether you are using a deployment template or a custom PowerShell script, somewhere near the beginning of the script you should set the current working directory to the root path of where the script is being executed from.

You do this by using the PowerShell cmdlet Set-Location.
Set-Location $PSScriptRoot

PowerShell’s Set-Location is akin to the DOS CD (change directory) command. Having set the location to the current working directory of the script, it is now very easy to reference other files that are in the root directory.

Referencing Files in a Flat Structure

As the current script location has already been set (Set-Location $PSScriptRoot) all that is required to reference files is to precede the filename with . (period backslash).

. means the path is relative to the current directory.

For example, to reference an MSI called App1.msi you would use the following syntax in the PowerShell deployment script: .App1.msi

Referencing a text file is the same: .MyTextFile.txt

I should point out that you can also use the automatic variable itself to reference the files should you prefer to: $PSScriptRootApp1.msi or $PSScriptRootMyTxtFile.txt and, arguably, it may make for better code legibility.

Referencing Files in Subdirectories

To reference files that are more structured and organized is as simple. If you have changed to the working directory of the script execution path in your deployment script (Set-Location $PSScriptRoot) then you can reference the files using the following syntax: ".MySubdirectoryMy Text File.txt".

Alternatively, you could achieve the same thing using the automatic variable $PSScriptRoot using the following syntax: "$PSScriptRootMySubdirectoryMy Text File.txt".

Note the use of quotes in the above examples. While not necessary in all cases, if you have a space anywhere in the path then quotes are required. As a habit, you should always use quotes even if the file path does not contain spaces.

Tip

Using $PSScriptRoot when referencing files instead of . negates the requirement of adding Set-Location $PSScriptRoot in your PowerShell deployment script as it already contains the full path to where the script is being executed from.

Here is a brief example for additional clarification: let’s say there is an image file called Wallpaper.jpg and it’s in a subdirectory of the root called Images. (See Figure 5-3)

A screenshot of a window. The panel on top highlights the file option. This P C is selected at the menu bar on the left. The panel on the right lists a file labeled wallpaper dot j p g.

Figure 5-3

The Wallpaper.jpg file you need to reference

If you have added the code Set-Location $PSScriptRoot at the start of your PowerShell deployment script, then the file would be referenced like this:

.ImagesWallpaper.jpg If you have not added the Set-Location code or you just want to anyway, you could reference the file using $PSScriptRoot because it already contains the full path of the script execution location. In this case, you can reference the file using the following syntax: $PSScriptRootImagesWallpaper.jpg.

To Me, To You, and Back Again

There may be a requirement where you must change the working directory from the script execution root path to an entirely new path by a different PowerShell provider.

You can do this by referencing the full path directly in the relevant PowerShell cmdlet.

Take the following scenario as an example:

The deployment script contains Set-Location $PSScriptRoot right at the very start of the script. The current working directory has now been set and the rest of the PowerShell code uses this to its advantage: various procedures are performed and files are referenced by beginning the path with . – for example, .SubDirectory1SubDirectory2image1.jpg.

Let’s say the script must now perform a lot of registry manipulation in the HKLM:SoftwareMyCompany and HKLM:SoftwareMyCompanyAttributes keys.

You could do this by specifying the full registry path in the cmdlets being used like so: New-ItemProperty -Path "HKLM:SoftwareMyCompany"

-Name "EmpNo01" -Value 001 | Out-Null

Listing 5-1 shows some example code of how this might look, and Figure 5-4 shows the resulting code execution.
Clear-Host
set-location $PSScriptRoot
Write-host "The current location is: $(Get-Location)" ↩
-ForegroundColor Cyan
Write-host "Making changes to the registry..." ↩
-ForegroundColor DarkCyan
New-ItemProperty -Path "HKLM:SoftwareMyCompany" -Name ↩ "EmpNo01" -Value 001 | Out-Null
New-ItemProperty -Path "HKLM:SoftwareMyCompany" -Name ↩ "EmpNo02" -Value 002 | Out-Null
New-ItemProperty -Path "HKLM:SoftwareMyCompany ↩
Attributes" -Name "New01" -Value 001 | Out-Null
New-ItemProperty -Path "HKLM:SoftwareMyCompany ↩
Attributes" -Name "New02" -Value 002 | Out-Null
Write-host "Registry changes have been made." ↩
-ForegroundColor DarkCyan
Write-host "The current location is: $(Get-Location)" ↩
-ForegroundColor Cyan
Listing 5-1

Writing to the registry - a different location to $PSScriptRoot

A screenshot of a dialog box titled administrator, windows powershell. It comprises a code written in 5 lines.

Figure 5-4

Shows the outcome of Listing 5-1

Code Breakdown

  1. 1.

    Line 1: The screen is cleared using Clear-Host.

     
  2. 2.

    Line 3: The current working directory is set to the path that the script is being executed from.

     
  3. 3.

    Line 5: Write-Host is used to display the working path which is C: emp.

     
  4. 4.

    Lines 9–12: Various changes are made to the registry using the New-ItemProperty cmdlet. Note the -path parameter contains the full location of the registry key being manipulated.

     
  5. 5.

    Line 16: The registry changes have been made and Write-Host is used to display that the working location has not changed. It is still in C: emp.

     

Now, there is nothing wrong with this method, but if you are changing location back and forth a lot in your script then there is another method that you should be aware of.

Push/Pop-Location

There are two PowerShell cmdlets that you can use to effortlessly change to a different location and back again: Push-Location and Pop-Location.

Push-Location

Push-Location is like Set-Location in that it will change to a new working directory. (Also like the DOS CD (change directory) command.)

The main and crucial difference is that it will remember where it came from. It “pushes” the current location to a location stack and if specified, will then change the current location to the location specified in the path. If the current location is C:Temp and you wish to change location to C:Windows the syntax is as follows: Push-Location C:Windows

When you are ready to return to the original location (C:Temp), you use the cmdlet: Pop-Location.

Pop-Location

The Pop-Location cmdlet changes the current location to the location most recently pushed onto the stack by using the Push-Location cmdlet. You do not need to add any parameters to Pop-Location to return from whence you came.

Let’s Try This Again

Changing to a new location using Push-Location now enables you to reference paths more easily using . (period backslash). You can push to locations all over the place knowing that with a simple pop you can easily revert to the location you just came from.

Listing 5-2 demonstrates how the code in Listing 5-1 might look if Push-Location and Pop-Location were used instead of full paths to the registry keys, and Figure 5-5 shows the outcome of the code execution.
Clear-Host
set-location $PSScriptRoot
Write-host "The current location is: $(Get-Location)" ↩
 -ForegroundColor Cyan
Write-host "Changing location to the relevant registry ↩
key in HKLM." -ForegroundColor Cyan
push-location "HKLM:softwareMyCompany"
Write-host "Push-Location. Current location is: ↩
$(Get-Location)" -ForegroundColor Yellow
Write-host "Making changes to the registry..." ↩
-ForegroundColor DarkCyan
New-ItemProperty -Path . -Name "EmpNo01" -Value 001 | Out-Null
New-ItemProperty -Path . -Name "EmpNo02" -Value 002 | Out-Null
New-ItemProperty -Path ".Attributes" -Name "New01" ↩
 -Value 001 | Out-Null
New-ItemProperty -Path ".Attributes" -Name "New02" ↩
-Value 002 | Out-Null
Write-host "Registry changes have been made." ↩
 -ForegroundColor DarkCyan
Pop-Location
Write-host "Pop-Location. The current location is: ↩
 $(Get-Location)" -ForegroundColor Cyan
Listing 5-2

Using Push-Location and Pop-Location to change to a new working directory and back again

A screenshot of a dialog box headed administrator, windows powershell. It comprises a code written in 7 lines.

Figure 5-5

Shows the outcome of Listing 5-2

Code Breakdown

  1. 1.

    Line 1: The screen is cleared using Clear-Host.

     
  2. 2.

    Line 3: The current working directory is set to the path that the script is being executed from.

     
  3. 3.

    Line 5: Write-Host is used to display the working path which is C: emp.

     
  4. 4.

    Line 8: Push-Location is used to change the working directory to a registry location, HKLM:softwareMyCompany.

     
  5. 5.

    Line 10: Write-Host is used to display the working path which is now HKLM:softwareMyCompany.

     
  6. 6.

    Lines 14–17: Various changes are made to the registry using the New-ItemProperty cmdlet. Note the -path parameter now contains current path abbreviations (. and .) to reference the required registry locations of the registry keys being manipulated.

     
  7. 7.

    Line 21: Pop-Location is used to return to the original location just came from.

     
  8. 8.

    Line 23: The registry changes have been made and Write-Host is used to display that the working location has returned to C: emp.

     

Choosing to use Push-Location and Pop-Location over specifying a full path in your PowerShell code is probably a stylistic choice for the short scripts that you will be writing and there is no wrong or right way. If you find that you are hopping around all over the place in your code, then it might make more sense to use these two cmdlets.

I chose to include it in this book as it is something that I always use and have used in the sample Deployment Template script that you will learn about later in the book – and as my intention is for you to fully understand all aspects of the script, it made sense then, to explain it here.

Summary

A short but tough chapter this one. You learned how to find out where the deployed PowerShell script is being executed from and then the two different ways you could place your files needed for a deployment.

It was explained how to reference those files and then how to reference new locations that are not held by the $PSScriptRoot automatic variable.

Finally, you learned an alternative method of navigation between locations using the Push-Location and Pop-Location cmdlets.

In the next chapter, you will learn how to invoke the installation of the application itself.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.169.94