Getting Started - All About Strings!
Welcome to part 9 of my series in getting started with Windows PowerShell!
In case you missed the earlier posts, you can check them out here:
Welcome to my Getting Started with Windows PowerShell series!
In case you missed the earlier posts, you can check them out here:
- Customizing your environment
- Command discovery
- Using the ISE and basic function creation
- A deeper dive into functions
- Loops
- Modules
- Help
- Accepting pipeline input
We will be exploring:
What's a string?
Back in Part 1, I mentioned that everything in PowerShell is an object. That's true! Today I'll be going over one object type, and that's System.String. A string in PowerShell is simply an object with that type.
Let's start by using the command Get-Location, and using the variable $ourPath to hold that object. We'll then get the value of the variable, and see what object type is returned.
$ourPath = Get-Location
Let's see what $ourPath returns.
Now let's pipe $ourPath to Get-Member and see what object type, methods, and properties are returned.
$ourPath | Get-Member
The object TypeName is System.Management.Automation.PathInfo. To get the string returned, we need to drill down into the Path property.
$ourPath.Path should return a TypeName of System.String.
There it is! Now that we know that, we can move on to string manipulation.
Manipulating Strings
Let's re-create the $ourPath variable and set it to become just the Path property of Get-Location. If you would like to follow along, open PowerShell and navigate to C:\PowerShell. Create a directory there named part9, and then navigate inside of that folder.
You can use the following sequence of commands to create the folder if it doesn't exist, and then navigate to it.
$path = 'C:\PowerShell\part9' New-Item -Path $path.SubString(0,$path.LastIndexOf('\')+1) -ItemType Directory -Name $path.SubString($path.LastIndexOf('\')+1) Set-Location $path
Now that we're inside of the part9 folder, we can use the following command to store the path in the $ourPath variable.
$ourPath = (Get-Location).Path
Note: the $ourPath variable should match the $path variable.
Now that we have our string stored in $ourPath, we can start manipulating it. I will be using the SubString and LastIndexOf methods.
What if you wanted to just get the value of the child folder you're currently in? In this case that folder name would be part9.
We can use both SubString and LastIndexOf to perform this task.
SubString
The SubString method accepts two overload arguments. They are separated by a comma, and are numerical. Value 1 (left) is the value of where you'd like to start the SubString, and value 2 is how many characters you'd like to move to the right of where you started. For example, if we run the following command:
$ourPath.SubString(0,8)
You can see that the values of (0,8) with the string 'C:\PowerShell\part9' returns C:\Power. That is because we start at the first character (0), and end after the value (8) is reached. Notice that from left to right, the letter 'r' is the eighth letter in the sequence.
Now that we know this, if we wanted to just return 'part9', we can use:
$ourPath.SubString(14,5)
There we go! We start out at (14), or 'p', and then end at (5), which puts us from p -> 9, returning part9.
For this example that's great, but what if we needed to make something auto-magically get the value of the child folder?
LastIndexOf
LastIndexOf accepts an overload argument that allows you to specify the character you'd like to look for. It will return the numerical value of its location in the string, the last time it is seen. That is to say, if we use the value '\' in a path, it will return the value of the where the very last occurrence of '\' is.
Let's take a look at:
$ourPath.LastIndexOf('\')
Awesome! This is handy as it will allow us to automatically get the name of the child folder, if need be. We would just need to start one value out from the LastIndexOf '\'.
Now we can combine SubString, and LastIndexOf. We'll leave the second value of SubString blank, which will essentially tell SubString where to start, and then to give us everything after that. We will add +1 after the LastIndexOf method is called to add one to the value returned.
$ourPath.Substring($ourPath.LastIndexOf('\')+1)
Let's take a look at another example of this in use. I will get a list of folders on my F:\ drive, and then use a ForEach-Object loop to iterate through and only display the folder names. You can do this with Get-ChildItem as well, but that wouldn't help this example :)
$folders = Get-ChildItem F:\ -Directory $folders | ForEach-Object { $_.FullName }
Now let's make that loop happen and only display the folder names.
$folders | ForEach-Object { $_.FullName.SubString($_.FullName.LastIndexOf('\')+1)}
While this has some practical uses, if you're using Get-ChildItem, it actually returns the Name property for you. We can use the following code to get the same result:
Get-ChildItem F:\ -Directory | Select-Object -ExpandProperty Name
Expanded Strings
An expanded string in PowerShell allows you to expand the values of variables inside of the string before it is executed and displayed. Expanded strings are surrounded in "double quotes". Let's take a look at this using the following code:
$test = 'This is a test' Write-Host "Test: [$test]"
You can see that the Write-Host displayed the value of the $test variable inside of the expanded string.
Let's take a look at another example, this time using Get-Process, looking for Chrome.
$process = Get-Process Chrome Write-Host "Process: $process"
Well that doesn't look nice! That's because there are both a lot of processes, as well as different properties of each process returned. The default isn't very pretty. If you want to expand an object's property inside of an expanded string, you'll need to encapsulate it inside of a sub-expression. Let's create a ForEach-Object loop, and then display the property name of each process in it.
$process | ForEach-Object { Write-Host "Process: $($_.Name)" }
That looks much better!
What if we wanted to display the actual variable name in the output, and not its value? To do this, we'll need to use the escape character, or `.
Let's take a look at that with the $test variable.
Write-Host "The value of `$test is: [$test]"
Literal Strings
Literal strings in PowerShell do not allow variable expansion, and will simply display what is inside of the quotes as-is. Literal strings are surrounded in 'single quotes'. Let's take a look at an example:
$test = 'This is a test' Write-Host 'This is a literal string: [$test]'
The -f Operator
The -f operator in PowerShell allows you to format strings in various predefined ways. You can apply formatting to characters and numbers. Here is one example of using the operator:
[array]$formatArray = @('you','values','them.') $user = (Get-ChildItem Env:\USERNAME).Value $date = Get-Date "Your user name is {0}, and the time is [{1:HH}:{1:mm}:{1:ss}]" -f $user,$date
For more information on how to use the format operator, check out this post:
Converting To and From Strings
In PowerShell, you can use the ToString method to convert an object to a string. You can also declare a variable, cast as [string]. Either way works. Let's look at the following code:
[int]$number = 10 $number | Get-Member
As expected, the object type for $number is Int32. Let's try converting that to a string via ToString.
$numberString = $number.ToString() $numberString | Get-Member
Aha! Now the type is a String!
Now, finally, let's look at casting the variable with explicit types.
[string]$number | Get-Member
We can also make it an int again, just as easily.
[int]$number | Get-Member
Building a ScriptBlock
We can use expanded strings to build a scriptblock, which we can then use for other PowerShell commands. Let's start by declaring the variable $findProcess with the process we'd like to find. Then we can create the expression via the [scriptblock] member, and the Create method. We'll then set that overload to the command we'd like to run.
Then we'll use the command Start-Job to start a PowerShell job, and run that command.
Here's the code:
$findProcess = 'chrome' $expression = [scriptblock]::Create("Get-Process $findProcess | Select-Object ProcessName, CPU, Path | Format-List") Start-Job -Name "$findProcess`Process" -ScriptBlock $expression
We used an expanded string to create the code being run in the script block, as well as to define the name of the job. We'll now use the following code to receive and clean up the job:
Receive-Job "$findProcess`Process" Get-Job "$findProcess`Process" | Remove-Job
As you can see the job is received, and we have the output of the command we created and executed via PowerShell jobs.
We used the expanded string to ensure we received and cleaned up the right job, and did so dynamically.
PowerShell jobs will be covered in a later portion of this series!
Homework
- Play around with all the different methods and properties of strings in PowerShell!
- For more ideas, check out this post on TechNet.
- Get a head start learning about PowerShell Jobs.
Get-Help about_jobs