Bootcamp: Powershell Olympics

Getting Started with Powershell

1) Enter the command Write-Host 'Hello, PowerShell!', then press Enter.

PS C:\Users\Sec504> Write-Host 'Hello, PowerShell!'

2) PowerShell commands and parameters options are not case-sensitive. Press the up arrow to return to the previous command, then change Write-Host to read write-host (lowercase). Press Enter to run the command.

PS C:\Users\Sec504> write-host 'Hello, PowerShell!'

3) PowerShell supports many different commands. Let's try another. Type Clear-Host then press Enter. You can also clear your screen by pressing CTRL+L.

PS C:\Users\Sec504> Clear-Host

4) Next, let's try a different PowerShell command: Get-ChildItem. This command lists files and objects.

PS C:\Users\Sec504> Get-ChildItem

5) Use tab completion to run the Get-NetAdapterAdvancedProperty by typing just a few characters, then press Enter.

PS C:\Users\Sec504> Get-NetAdapterAdvancedProperty

6) Use Get-ChildItem to list the contents of the C:\Program Files (x86) directory by typing just a few characters

PS C:\Users\Sec504> Get-ChildItem 'C:\Program Files (x86)\'

7) Run Get-Verb to see a list of approved PowerShell verbs.

PS C:\Users\Sec504> Get-Verb

8) Next, let's look at some popular Verb-Noun PowerShell functionality. Run the Get-Date command.

PS C:\Users\Sec504> Get-Date

9) Next, type Get-Volume, then press Enter.

PS C:\Users\Sec504> Get-Volume

10) Next, let's try a different verb. Type the Start-Process Notepad, then press Enter.

PS C:\Users\Sec504> Start-Process Notepad

11) Next, let's look at the Get-Process command. Type Get-Process Notepad, then press Enter.

PS C:\Users\Sec504> Get-Process Notepad

12) Next, type Stop-Process Notepad, then press Enter.

PS C:\Users\Sec504> Stop-Process -Name Notepad

13) Let's investigate the Start-Process command further. We can use Get-Command to collect additional information about PowerShell commands. Type Get-Command -Name Start-Process, then press Enter.

PS C:\Users\Sec504> Get-Command -Name Start-Process

14) Let's take a look at another command using Get-Command. Type Get-Command -Name Get-Volume, then press Enter.

PS C:\Users\Sec504> Get-Command -Name Get-Volume

15) Type Get-Command -Noun Volume, then press Enter.

PS C:\Users\Sec504> Get-Command -Noun Volume

16) Aliases are shortcuts to run PowerShell commands. Instead of Get-ChildItem, you can run the dir command.

PS C:\Users\Sec504> dir

17) You can use the Get-Alias command to look up the command associated with an alias. Type Get-Alias Dir, then press Enter.

PS C:\Users\Sec504> Get-Alias Dir

18) Type Get-Alias -Definition Get-ChildItem, then press Enter.

PS C:\Users\Sec504> Get-Alias -Definition Get-ChildItem

19) Find an alias for Get-Timezone.

PS C:\Users\Sec504> Get-Alias -Definition Get-TimeZone

20) Next, find out which command uses the alias ps.

PS C:\Users\Sec504> Get-Alias ps

21) Type Get-Help, then press Enter to display PowerShell's help system information.

PS C:\Users\Sec504> Get-Help

22) Get-Help also provides instructions for specific commands. Run Get-Help Get-Process to get help information for the Get-Process cmdlet.

PS C:\Users\Sec504> Get-Help Get-Process

23) When you run Get-Help, the help information displays all at once. Most of the time, we want to read the help documentation one screen at a time. This is the behavior of the Help function.

Type Help Get-Process, then press Enter. Press the spacebar several times to get to the end of the help information, then run next to continue.

PS C:\Users\Sec504> Help Get-Process

24) But there's more! Type Get-Help -Examples Get-Process, then press Enter. Scroll up to scan through the help information.

PS C:\Users\Sec504> Get-Help -Examples Get-Process

25) PowerShell also provides high-level help information. Type Get-Help about_Core_Commands, then press Enter.

PS C:\Users\Sec504> Get-Help about_Core_Commands

26) There are many other PowerShell about help subjects. Type Get-Help about*, then press Enter.

PS C:\Users\Sec504> Get-Help about*

27) Type ping 127.0.0.1, then press Enter to use the ping.exe program.

PS C:\Users\Sec504> PING.EXE 127.0.0.1

28) Type sc query, then press Enter. PowerShell will prompt you for an option; press Enter when prompted.

PS C:\Users\Sec504> sc.exe query

Working with the Pipeline

1) Let's start with a straightforward command. Type Get-Service, then press Enter.

PS C:\Users\Sec504> Get-Service

2) The Get-Service cmdlet allow us to interrogate the services running on the Windows system. There are a lot of services though, so it can be difficult to catch all of the output.

Press the up arrow to recall the Get-Service command. At the end of the line add a space followed by | more, then press Enter. Scroll through the output by pressing the spacebar multiple times until you return to the prompt.

PS C:\Users\Sec504> Get-Service | more

3) Use Sort-Object as a pipeline command to change the sort order of the Get-Service output to alphabetically descending. Type Get-Service | Sort-Object -Descending, then press Enter.

PS C:\Users\Sec504> Get-Service | Sort-Object -Descending

4) Create a pipeline to sort the output of Get-Process by name. Type Get-Process | Sort-Object -Property Name, then press Enter.

PS C:\Users\Sec504> Get-Process | Sort-Object -Property Name

5) In this output we see that Sort-Object has sorted the output by the Name property. You can also sort by process ID using the Id property.

PS C:\Users\Sec504> Get-Process | Sort-Object -Property Id

6) Sort-Object can also make the output unique. This can be useful to identifying the name of each item, eliminating duplicates.

Retrieve the process list again, sorting by name in alphabetically descending order. Add the -Unique argument to make the list of processes unique.

PS C:\Users\Sec504> Get-Process | Sort-Object -Property Name -Descending -Unique

7) Like other shells, PowerShell supports redirection operators such as > to send the output of the pipeline to a file.

Run the PowerShell Get-Process, redirecting the output to a file in the default user profile directory called processes1.txt

PS C:\Users\Sec504> Get-Process > processes1.txt

8) The redirection operator > allows us to create a file with the output of the pipeline, but we have little flexibility in defining the format of the file. This is where the cmdlet Out-File is useful.

Press the up arrow to recall the previous command. Instead of using the redirection operator, create a pipeline after Get-Process adding Out-File -FilePath processes2.txt

PS C:\Users\Sec504> Get-Process | Out-File -FilePath processes2.txt

8) When you use the redirection operator > or Out-File, PowerShell takes the pipeline output and creates a little-endian UTF-16 unicode text file with a Byte Order Mark (BOM) at the beginning of the file. That is, these look like text files, but they aren't plain ASCII files.

To create a plain ASCII text file, use Out-File with the parameter -Encoding ASCII. Run the previous command again, this time creating an ASCII file called processes3.txt

PS C:\Users\Sec504> Get-Process | Out-File -FilePath processes3.txt -Encoding ascii

9) Run Get-ChildItem processes* .Notice how the third file (the ASCII file) is approximately half the size of the other two. This is because UTF-16 format requires two bytes per ASCII character.

10) Examine the first several lines of the processes3.txt file. Type Get-Content -Path processes3.txt -First 5, then press Enter.

PS C:\Users\Sec504> Get-Content -Path .\processes3.txt -First 5

11) No surprise here, the content of processes3.txt is just like what we saw when we ran Get-Process output in the terminal. Adding Out-File just redirects the output to a file.

What if you want the output to go to the screen and go to a file? This is the job of the Tee-Object cmdlet and the PowerShell pipeline. Type Get-Process | Tee-Object -FilePath processes4.txt, then press Enter.

PS C:\Users\Sec504> Get-Process | Tee-Object -FilePath processes4.txt

Tee-Object duplicated the output of Get-Process, showing it on the screen and saving it to processes4.txt

12) PowerShell also supports other output mechanisms, such as Export-Csv. Create a list of processes, sending the output to the pipeline with Export-Csv -Path processes.csv.

PS C:\Users\Sec504> Get-Process | Export-Csv -Path processes.csv

Export-Csv took the output of Get-Process and converted it into a CSV file, allowing us to process the data with other tools.

13) Take a look at the first several lines of processes.csv using Get-Content. Limit the output to the first 5 lines.

PS C:\Users\Sec504> Get-Content -Path .\processes.csv -First 5

This is a lot more information than what we saw when we used Get-Process | Out-File. Earlier we saw 8 columns of information but the CSV file has over 60 columns!

This highlights an important concept about the PowerShell pipeline: PowerShell passes objects in the pipeline, not just text. An object is a collection of code (methods) and data properties that represents the item. Type next then press Enter to continue.

14) This is an important concept. When you run a PowerShell command and send the output in a pipeline, you are sending an object or a collection of objects to the next step in the pipeline. These objects can include more information than what you see by default.

Using PowerShell, we can retrieve the information that is important to us using different commands. Let's try it now. Type Get-Process -Name lsass | Select-Object -Property *, then press Enter.

PS C:\Users\Sec504> Get-Process -Name lsass | Select-Object -Property *

15) Use Get-Process to collect the default properties for the rexplorer process.

PS C:\Users\Sec504> Get-Process -Name rexplorer

Get-Process shows some information, but let's gather more data. Let's examine summary information about the object returned by Get-Process using the PowerShell pipeline.

16) Run Get-Process -Name rexplorer | Measure-Object

PS C:\Users\Sec504> Get-Process -Name rexplorer | Measure-Object

Measure-Object returns information about the numeric properties of the objects received in the pipeline. In this example, Measure-Object tells us that there are 2 objects in the pipeline, corresponding to the two instances of the rexplorer process. We'll return to Measure-Object when we look at file processing.

17) Next, let's look at the object members. Run Get-Process -Name rexplorer | Get-Member

PS C:\Users\Sec504> Get-Process -Name rexplorer | Get-Member

Get-Member returns information about the object properties and methods received in the pipeline. For Get-Process, we see lots of interesting properties about the processes, but no values.

18) To see the values and the property names, run Get-Process -Name rexplorer | Select-Object -First 1 -Property *

PS C:\Users\Sec504> Get-Process -Name rexplorer | Select-Object -First 1 -Property *

In the previous command we used Select-Object to get a list of the properties available, limiting it to the first object returned with -First 1 to avoid repeating the output for the two rexplorer processes. In this output we see the same property names that we saw with Get-Member, but we can also see the values for the first object.

This type of analysis is called introspection: the ability to examine properties of an object at runtime. We'll use Get-Member and Select-Object -Property * often to see which properties are available when working with PowerShell objects.

19) Let's retrieve specific properties about the rexplorer process using Select-Object. Instead of using -Property *, we can specify a comma-separated list of properties that we want to see.

Run Get-Process -Name rexplorer | Select-Object -Property Name, Id, Path to get the process name, process ID, and process path information.

PS C:\Users\Sec504> Get-Process -Name rexplorer | Select-Object -Property Name, Id, Path

20) Repeat the last command by pressing the up arrow, then add two additional properties: CPU and WorkingSet64

PS C:\Users\Sec504> Get-Process -Name rexplorer | Select-Object -Property Name, Id, Path, CPU, WorkingSet64

21) Press the up arrow to recall the previous command and extend the pipeline, adding Format-Table as the last element.

PS C:\Users\Sec504> Get-Process -Name rexplorer | Select-Object -Property Name, Id, Path, CPU, WorkingSet64 | Format-Table

22) Many of the associated PowerShell nouns work together in a pipeline. You can use a PowerShell command such as Get-Process, then stop the target process by adding Stop-Process to the pipeline with no parameters.

Type Get-Process -Name rexplorer | Stop-Process then press Enter to terminate the rexplorer processes.

PS C:\Users\Sec504> Get-Process -Name rexplorer | Stop-Process

23) Since PowerShell is designed around the concept of using a pipeline, there are lots of cmdlets that allow us to leverage this functionality. We can take the output of Get-Process and export the results to an HTML report using ConvertTo-HTML, for example.

Run Get-Process | Select-Object -Property Name, Id, Path, CPU, WorkingSet64 | ConvertTo-Html | Out-File processes.html to create an HTML report of all running processes, saving the output as processes.html

PS C:\Users\Sec504> Get-Process | Select-Object -Property Name, Id, Path, CPU, WorkingSet64 | ConvertTo-Html | Out-File processes.html
PS C:\Users\Sec504> Start-Process .\processes.html

24) Once you understand the concepts around PowerShell pipelines, it can be applied to lots of different functionality. For example, we can get basic information about the Event Log service by running Get-Service -Name eventlog

PS C:\Users\Sec504> Get-Service -Name EventLog

25) Press the up arrow to recall the previous command. Use Select-Object in a pipeline to retrieve the following fields about the Event Log service: Status, Name, DisplayName, and StartType

PS C:\Users\Sec504> Get-Service -Name EventLog | Select-Object -Property Status, Name, DisplayName, StartType
PS C:\Users\Sec504> Get-Service -Name EventLog | Select-Object -Property *

26) Press the up arrow to recall that command, then display the results in a table format.

PS C:\Users\Sec504> Get-Service -Name EventLog | Select-Object -Property * | Format-Table

27) So far we've started out pipeline examples with Get-Process and Get-Service, but that doesn't have to be the start of the pipeline. Examine the status of the WinRM service: type 'winrm' | Get-Service then press Enter.

PS C:\Users\Sec504> 'winrm' | Get-Service

In this command we created a string object 'winrm' as the input to the Get-Service cmdlet.

27) Type 'winrm' | Get-Member to see all of the string properties.

PS C:\Users\Sec504> 'winrm' | Get-Member

28) Run Get-Content -Path services.txt

PS C:\Users\Sec504> Get-Content -Path .\services.txt

29) This file has several services listed. We can quickly interrogate all of the services by leveraging PowerShell parameter binding in the pipeline.

Press the up arrow to recall the previous Get-Content command, then add Get-Service to the pipeline.

PS C:\Users\Sec504> Get-Content -Path .\services.txt | Get-Service

30) Run 'rexplorer' | Stop-Process

PS C:\Users\Sec504> 'rexplorer' | Stop-Process

Stop-Process returns an error here, not because it doesn't support parameter binding (it does), but because it can't accept a string as the default parameter. However, you can build a pipeline starting with Get-Process -Name rexplorer, followed by Stop-Process. Do that now to stop the rexplorer process.

PS C:\Users\Sec504> Get-Process -Name rexplorer | Stop-Process

31) Get a list of running services using Where-Object by typing Get-Service | Where-Object -Property Status -EQ Running, then press Enter.

PS C:\Users\Sec504> Get-Service | Where-Object -Property Status -EQ Running

32) Type Get-Service | Where-Object -Property DisplayName -Like 'Application*' then press Enter.

PS C:\Users\Sec504> Get-Service | Where-Object -Property DisplayName -Like 'Application*'

33) Use Get-Process to identify all processes running from a path that includes the string temp.

PS C:\Users\Sec504> Get-Process | Where-Object -Property Path -Like "*temp*"

Here we identifed all processes running from a directory with temp anywhere in the name. This is useful for incident response, since non-malicious processes rarely launch from temporary directories.

34) Press the up arrow to recall the previous command. Use the pipeline to retrieve multiple details about these processes including the name, ID, path, and start time.

PS C:\Users\Sec504> Get-Process | Where-Object -Property Path -Like "*temp*" | Select-Object -Property Name, Id, Path, StartTime

35) Now, extend the pipeline to sort the results by StartTime.

PS C:\Users\Sec504> Get-Process | Where-Object -Property Path -Like "*temp*" | Select-Object -Property Name, Id, Path, StartTime | Sort-Object -Property StartTime

36) Export this analysis into a CSV file named malicious-processes.csv and an HTML report named malicious-processes.html

PS C:\Users\Sec504> Get-Process | Where-Object -Property Path -Like "*temp*" | Select-Object -Property Name, Id, Path, StartTime | Sort-Object -Property StartTime | Export-Csv -Path malicious-processes.csv
PS C:\Users\Sec504> Get-Process | Where-Object -Property Path -Like "*temp*" | Select-Object -Property Name, Id, Path, StartTime | Sort-Object -Property StartTime | ConvertTo-Html | Out-File -FilePath malicious-processes.html

37) Next, terminate all of the processes running from temporary directories.

PS C:\Users\Sec504> Get-Process | Where-Object -Property Path -Like "*temp*" | Select-Object -Property Name | Stop-Process

39) Remove the files starting with services in the file name.

PS C:\Users\Sec504> Get-ChildItem -Name "services*" | Remove-Item

1) Navigating the file system is an essential skill for using PowerShell well. Start by examining your current directory.

Run Get-Location to examine your current directory.

PS C:\Users\Sec504> Get-Location

2) You can also use the alias pwd for Get-Location. Try running the alias for Get-Location now.

PS C:\Users\Sec504> pwd

3) In PowerShell you can use Set-Location to change to a different directory. Use Set-Location to change to the C:\temp\bobsled directory, then run Get-Location to display the current directory.

PS C:\Users\Sec504> Set-Location C:\Temp\bobsled
PS C:\Users\Sec504> Set-Location C:\Temp\bobsled

4) In the previous command you used an absolute directory reference, but PowerShell also supports a relative directory reference.

Use Set-Location to go back one directory by running Set-Location .. then run Get-Location to display the current directory.

PS C:\Temp\bobsled> Set-Location ..
PS C:\Temp> Get-Location

5) Next, return to the bobsled directory, this time using the relative path name with Set-Location, then run Get-Location to display the current directory.

PS C:\Temp> Set-Location bobsled
PS C:\Temp\bobsled> Get-Location

6) Next, let's create a new directory. Creating directories in PowerShell is the job of the New-Item cmdlet. To create a directory, specify -ItemType Directory and the name of the directory using -Name DirectoryName.

Use New-Item to create the directory sled (you need to already be in the C:\temp\bobsled directory).

PS C:\Temp\bobsled> New-Item -Name sled -ItemType Directory

7) PowerShell will let you specify multiple directories in one command, creating each needed sub-directory. Run the New-Item command again, this time creating the following nested directories for a 4-person bobsled team: Brakeman\Pusher\Pusher\Pilot.

PS C:\Temp\bobsled> New-Item -ItemType Directory -Name Brakeman\Pusher\Pusher\Pilot

8) The New-Item syntax to create directories can be simplified using the mkdir function: mkdir DirName. Create the directory structure using mkdir for a 2-person bobsled team: Brakeman\Pilot.

PS C:\Temp\bobsled> mkdir Brakeman\Pilot

9) When you want to remove a directory, you can use Remove-Item followed by the directory name. Remove the sled directory using the Remove-Item cmdlet.

PS C:\Temp\bobsled> Remove-Item .\sled

10) PowerShell will prompt you if you try to remove a directory that has sub-directories or files in it. You can add the -Recurse argument to remove a directory and everything in it without a prompt. Remove the brakeman directory and sub-directories using Remove-Item. Add -Recurse to remove the directories without a prompt.

PS C:\Temp\bobsled> Remove-Item .\Brakeman -Recurse

11) Next we'll look at the powerful cmdlet Get-ChildItem. This cmdlet allows us to list items and child items in one or more directories.Run the Get-ChildItem cmdlet with no arguments. Make sure you are in the C:\temp\bobsled directory. Note that we've added some files for your analysis.

PS C:\Temp\bobsled> Get-ChildItem

12) Get the content of the data folder. Use -Name also.

PS C:\Temp\bobsled> Get-ChildItem data
PS C:\Temp\bobsled> Get-ChildItem -Name data

13) Run the previous command again, this time adding -Recurse to display file and directory names in all subdirectories.

PS C:\Temp\bobsled> Get-ChildItem -Name data -Recurse

14) Let's focus on the files in the data/1952 directory. Change to this directory, then run Get-Location. Then list the files in this directory.

PS C:\Temp\bobsled> Set-Location .\data\1952
PS C:\Temp\bobsled\data\1952> Get-Location
PS C:\Temp\bobsled\data\1952> Get-ChildItem

15) By default, Get-ChildItem doesn't list files that have the hidden attribute set. To display hidden files, add the -Force argument. Run the previous command again, this time adding -Force.

PS C:\Temp\bobsled\data\1952> Get-ChildItem -Force

16) Using Get-ChildItem you can search for file or directory names by specifying a name as an argument. When you add -Recurse, you can search all subdirectories as well.

Search for the file named Hans_He-GER-Bronze.txt.

PS C:\Temp\bobsled> Get-ChildItem -Recurse 'Hans_He-GER-Bronze.txt'

17) You can also use the wildcard * in the file name to perform partial name matches. Use Get-ChildItem with a wildcard to identify all Gold medal winners.

PS C:\Temp\bobsled> Get-ChildItem -Recurse '*Gold*'

18) PowerShell also allows you to exclude named with the -Exclude argument. PowerShell also allows you to exclude named with the -Exclude argument.

PS C:\Temp\bobsled> Get-ChildItem -Name .\data\1998 -Exclude "*Gold*"

19) The Get-ChildItem cmdlet is especially powerful, not just because you can list files and directories, but also because it allows you to examine other PowerShell Drives as well.

We normally think of drives as a drive letter (C:, E:, etc.), but PowerShell also supports other drive prefixes. Run the Get-PsDrive cmdlet to see a list of PPowerShell drives on the system.

PS C:\Temp\bobsled> Get-PSDrive

The output of Get-PSDrive shows us other PowerShell drive prefixes that we can also interrogate with Get-ChildItem.

20) Examine the contents of the Env drive prefix using Get-ChildItem.

PS C:\Temp\bobsled> Get-ChildItem Env:

21) Repeat the prior command, this time examining the contents of the HKCU PowerShell Drive.

PS C:\Temp\bobsled> Get-ChildItem HKCU:

HKCU is an alias for the Windows registry hive HKEY_CURRENT_USER. Since PowerShell treats this as a drive, we can use Get-ChildItem to interrogate the registry.

22) Repeat the prior command, this time specifying the registry location HKCU:\Software.

PS C:\Temp\bobsled> Get-ChildItem HKCU:\SOFTWARE

23) Here we see the Software registry key. Within this key we see several subkeys, including Microsoft. Repeat the prior command, this time examining the contents of the HKCU:\Software\Microsoft key.

PS C:\Temp\bobsled> Get-ChildItem HKCU:\SOFTWARE\Microsoft\

24) As you can see, we can navigate the contents of the registry hive very much like we navigate a conventional file system. Examine the registry key values in the HKCU:\Software\Monobob2022 key.

PS C:\Temp\bobsled> Get-ChildItem HKCU:\SOFTWARE\Monobob2022\

25) Repeat the last command, enumerating the contents of each of these registry keys by adding the -Recurse option.

PS C:\Temp\bobsled> Get-ChildItem HKCU:\SOFTWARE\Monobob2022\ -Recurse

26) Repeat the following command, this time adding the pipeline Where-Object -Property Name -Match "Qing" to find the key matching the Olymplic athlete name.

PS C:\Temp\bobsled> Get-ChildItem HKCU:\SOFTWARE\Monobob2022\ -Recurse | Where-Object -Property Name -Match "Qing"

27) Next, let's investigate one more PowerShell Drive provider: system certificates. Use Get-ChildItem to examine the Cert: drive.

PS C:\Temp\bobsled> Get-ChildItem Cert:

28) Examine the trusted root certificate authorities on the local system using Get-ChildItem Cert:\LocalMachine\Root

PS C:\Temp\bobsled> Get-ChildItem Cert:\LocalMachine\Root\

Working with Powershell Variables

PowerShell has support for variables: named objects that hold data and code. First we'll look at PowerShell's automatic variables.

1) PowerShell has several automatic variables available to every PowerShell session that describes the environment. Let's examine several of them.

PS C:\Users\Sec504> $Host

2) Examine the available members by typing $Host | Get-Member, then press Enter.

PS C:\Users\Sec504> $Host | Get-Member

The $Host variable is an object, just like everything else in PowerShell. Here we see the names of the properties and the methods. We can access these object members using dot notation.

3) Access the Version property of the $Host variable: type $Host.Version, then press Enter.

PS C:\Users\Sec504> $Host.Version

Like $Host, $Host.Version is also a PowerShell object. Accessing this member shows the table format for the major, minor, build, and revision members. We can see all of the members in this object like we did for $Host using dot notation.

4) Run the previous command with Get-Member .

PS C:\Users\Sec504> $Host.Version | Get-Member

5) Here we see the list of properties for the $Host.Version property. If you want to access just the Major value you can reference this member directly using more dot notation.

PS C:\Users\Sec504> $Host.Version.Major

6) You can also invoke the methods associated with the $Host.Version object by specifying the method name followed by () (sometimes with a value inside the parenthesis).

Invoke the ToString() method by typing $Host.Version.ToString(), then press Enter.

PS C:\Users\Sec504> $Host.Version.ToString()

7) Let's take a look at a few more useful variables. Type $Home then press Enter.

PS C:\Users\Sec504> $HOME

9) We've created a file C:\TEMP\report.html; copy it to your user profile directory by typing Copy-Item C:\TEMP\report.html $Home

PS C:\Users\Sec504> Copy-Item C:\Temp\report.html $HOME

10) The $Error automatic variable keeps track of all the times your commands generated an error for the current session. This is valuable since your custom PowerShell programs can reference error messages to provide help to users.

PS C:\Users\Sec504> good
PS C:\Users\Sec504> $Error

11) We'll look at one more automatic variable: $?. First, run Get-ChildItem -Name report.html

PS C:\Users\Sec504> Get-ChildItem -Name report.html
PS C:\Users\Sec504> $?

Notice how $? returns True. True is a Boolean data type; that is, it is either True or False. The $? variable indicates if the last command ran successfully. The output True here indicates that the Get-ChildItem command ran successfully.

12) Let's look at another case: Type Get-ChildItem -Name report.txt, then press Enter. Then type $? .

PS C:\Users\Sec504> Get-ChildItem -Name report.txt
PS C:\Users\Sec504> $?

Notice how the value of $? is now set to False. This tells us the previous command did not run successfully. This is valuable in PowerShell scripts to test if the previous command returned an error. PowerShell has other automatic variables as well, you can read about them by running help about_Automatic_Variables.

13) You may remember this from the PowerShell Olympics Using the Pipeline event. Get-Process retrieves a list of process details.

Run the command again, this time creating a variable name $processes to store the process information by typing $processes = Get-Process, then press Enter.

PS C:\Users\Sec504> $processes = Get-Process

Type $processes and press Enter.

PS C:\Users\Sec504> $processes

14) Declare a new process information variable: type $pnow = Get-Process, then press Enter.

PS C:\Users\Sec504> $pnow = Get-Process

We can compare the $processes and $pnow variables using Compare-Object. Type Compare-Object $processes $pnow, then press Enter.

Notice how Compare-Object examines the two variables and shows us the differences? This is a powerful feature of PowerShell variables: they allow us to save a point-in-time representation of any object output, then compare it to another similar variable later.

15) In the output of Compare-Object we see the rexplorer process is back. Type $targetproc = Get-Process -Name rexplorer then press Enter.

PS C:\Users\Sec504> $targetproc = Get-Process -Name rexplorer

Notice how this time the variable holds just the process information for rexplorer, corresponding to the -Name argument of the Get-Process command. We can continue to leverage the features of different PowerShell commands as needed to refine what is represented in the variable.

16) Use the PowerShell pipeline to examine the members of the $targetproc variable with Get-Member.

PS C:\Users\Sec504> $targetproc | Get-Member

Scroll up a bit and examine some of the methods and properties associated with the object. Notice the Kill() method that can be invoked to kill the processes identified in the $targetproc variable. Methods for an object can be invoked using dot notation ObjectName.Method().

17) Invoke the Kill() method on the $targetproc variable to terminate the two processes using dot notation.

PS C:\Users\Sec504> $targetproc.Kill()

By calling the Kill() method on the $targetproc variable you terminated both the rexplorer processes. You could have used the pipeline, sending the variable to Stop-Process as well; which one you choose is a matter of preference.

18) Let's start by declaring a variable that represents a number. Type $limit = 10, then press Enter.

PS C:\Users\Sec504> $limit = 10

19) Like everything in PowerShell, $limit is an object. Take a look at the members of this object by running $limit | Get-Member

PS C:\Users\Sec504> $limit | Get-Member

At the top of this output look at the line starting with TypeName. When you declared the $limit variable with the value 10, PowerShell decided to use a type of Int32 (a 32-bit integer) to represent this data. The methods associated with this object are mostly for converting this to other types. Let's invoke one of those methods now.

20) Type $limit.GetType() then press Enter.

PS C:\Users\Sec504> $limit.GetType()

21) PowerShell is a dynamically typed scripting language, which means that every variable has a type, but that variable type can change (it's dynamic). Let's experiment with that now: type $limit = '100' (with the quotation marks), then press Enter.

PS C:\Users\Sec504> $limit = '100'

Press the up arrow a few times, recalling the $limit | Get-Member command, then press Enter.

PS C:\Users\Sec504> $limit = '100'

If you scroll up again you'll see the type has changed. This time, $limit is a String type with different methods and properties. When you specify quotation marks around a value, PowerShell will treat it as a string. Numbers assigned to a variable without quotations will be assigned a type of Int32 or other numeric types depending on the number selected.

22) Next, let's look at something cool and useful. Type $limit = 100MB, then press Enter.

PS C:\Users\Sec504> $limit = 100MB
PS C:\Users\Sec504> $limit | Get-Member
PS C:\Users\Sec504> $limit

Instead of $limit having a value of 100, it has a value of 104857600, the number of bytes in 100 MB. PowerShell is designed to be "administrator first", with handy integer literals to interpret values including kilobytes, megabytes, gigabytes, terabytes, and petabytes.

23) PowerShell can also work with converting hexadecimal and binary values using the prefix 0x or 0b. Change $limit to 0x31337 now.

PS C:\Users\Sec504> $limit = 0x31337
PS C:\Users\Sec504> $limit

24) Next, let's look at another type: arrays. PowerShell arrays hold zero or more elements denoted by @() notation. Create a PowerShell array: type $alpinecourses = @('Rock', 'Ice River', 'Nile') then press Enter.

PS C:\Users\Sec504> $alpinecourses = @('Rock', 'Ice River', 'Rainbow')

Access the last element of the array. Type $alpinecourses[2], then press Enter.

PS C:\Users\Sec504> $alpinecourses[2]

Access the first element of the array.

PS C:\Users\Sec504> $alpinecourses[0]

25) Retrieve a list of the Windows services using Get-Service, saving it in a variable called $services.

PS C:\Users\Sec504> $services = Get-Service

Call the GetType() method on the $services variable.

PS C:\Users\Sec504> $services.GetType()

The $services variable has a type of Object[], but notice how the base type indicates that it is an array. We can use the array subscript notation to access different elements in this variable as well.

PS C:\Users\Sec504> $services[10]

26) We'll look at one more variable type: DateTime. Type Get-Date | Get-Member, then press Enter.

PS C:\Users\Sec504> Get-Date | Get-Member

The PowerShell Get-Date command returns a DateTime type which represents the date and time when you invoke the command. We can use this command to record a start and ending time for an operation (such as a long-running job). Let's do that now.

27) Create two variables, $start and $stop using Get-Date, with a delay of 3 seconds between using Start-Sleep 3. We'll use the command separator ; to run all three commands on one line. Type $start = Get-Date ; Start-Sleep 3 ; $stop = Get-Date then press Enter.

PS C:\Users\Sec504> $start = Get-Date; Start-Sleep 3; $stop = Get-Date

Subtract $stop from $start to see the time difference: $stop - $start

PS C:\Users\Sec504> $stop - $start

The TotalSeconds property will show you the time delay between the two Get-Date commands, which will be just over 3 seconds. Get-Date will return the current date, but we can also specify an arbitrary date.

28) Create a $future variable string of Feb. 8, 2030 at 9:00 AM (use MM/DD/YYYY or DD/MM/YYYY based on your regional convention; add a space after the year then 9:00 AM for the time).

PS C:\Users\Sec504> $future = "08/02/2030 9:00 AM"

Try to subtract the $start object from $future.

PS C:\Users\Sec504> $future - $start

We know that $future is a string object, since we declared it using quotes. We received an error because we can't perform arithmetic using a string and a DateTime object. We need to convert the string to a DateTime object using the cast operator.

29) In PowerShell, you can specify a type in square brackets before the variable name to convert it to the specified type. Let's try that now.

Type [DateTime]$future, then press Enter.

PS C:\Users\Sec504> [DateTime]$future

PowerShell converted the string in $future to a DateTime object.

30) Press the up arrow several times to return to the subtraction operation and add a typecast to calculate the time span difference between $future and $start.

PS C:\Users\Sec504> [DateTime]$future - $start

31) PowerShell can easily embed variables inside of strings. To practice this, create a variable called $favcolor with a value of 'gold'.

PS C:\Users\Sec504> $favcolor = 'gold'

Send a message to the console, using string substitution to expand the $favcolor variable. Type Write-Host "My favorite color is $favcolor."

PS C:\Users\Sec504> Write-Host "My favorite color is $favcolor."

Press the up arrow to recall the last command and change the double quotes to single quotes, then press Enter.

PS C:\Users\Sec504> Write-Host 'My favorite color is $favcolor.'

32) Along with string substitution, we also have escape sequences in strings. The backtick character is used to indicate an escape sequence, followed by an escape sequence character. For example, `n is used to indicate a newline.

We can create a prompt to accept user input with Read-Host. Type $age = Read-Host "Please enter your age.`nBe honest please" then press Enter. Enter a value when prompted, then press Enter.

PS C:\Users\Sec504> $age = Read-Host "Please enter your age.`nBe honest please"

Here we used ` to indicate that a newline character should be inserted in the string. The Read-Host command prompts the user for input and saves it in the specified variable. Examine the contents of the $age variable to see your answer.

PS C:\Users\Sec504> $age

Last updated