- Poll: How reliable are ChatGPT and Bing Chat? - Tue, May 23 2023
- Pip install Boto3 - Thu, Mar 24 2022
- Install Boto3 (AWS SDK for Python) in Visual Studio Code (VS Code) on Windows - Wed, Feb 23 2022
The purpose of variables in any programming language is to store data items so you can reuse them later in your code. If you only know variables from batch scripts, you’ll be surprised at how many more things you can do with a PowerShell variable.
Naming
Let’s look at the basics first. An important property of a PowerShell variable is its name, which is always preceded by the dollar sign “$” and can only contain letters, numbers, and the underscore. If you feel a strong urge to use other characters, you have to enclose the name in curly braces. You should not use the name of variables that have been pre-defined (more about that later).
Here are examples of valid variable names:
$myVariable, $MyVariable_1, ${my-variable}
And these are invalid names:
myVariable, $my-variable, $my variable
Strictly speaking, the variable name is the part after the dollar sign. This is important to know because when you have to specify the variable name as a parameter in a cmdlet, you have to enter it without the dollar sign. The dollar sign tells the shell to read the variable's value.
As most keywords in PowerShell, variables are case-insensitive. Thus, PowerShell does not distinguish between $myVariable and $Myvariable.
Values
You can assign values to a PowerShell variable by combining a variable name, an assignment operator, and an expression. Here is a simple example:
$a = 1 + 1
The “=” sign is one of eight assignment operators. An expression is everything for which PowerShell can determine a value. If you enter an expression at a PowerShell prompt, PowerShell returns its value. “Hello world” and 1 are also expressions; determining their values just doesn’t need so many calculations.
If you want to populate multiple variables with the same value, you can save some typing as in the example below:
$a = $b = $c = 1
You can also define multiple variables with different values on one line:
$a, $b, $c = 1, 2, 3
This reduces the number of lines in your script but also makes it harder to read.
Other ways exist to store a value in a variable. We will see examples later.
To display the value of a variable, you don’t need a special command as in many other programming languages; entering the variable name is enough. This works in a script and on a command prompt.
$c
Thanks to the variable interpolation, you can also expand a variable in a string if the string is enclosed in double quotation marks.
"These are the values of the variables: $a, $b, $c."
If you want to display the variable names as text instead of displaying their values, you have to enclose the string in single quotation marks.
'These are the names of our variables $a, $b, $c.'
In this case, PowerShell doesn’t recognize $a, $b, and $c at all as variables—just as ordinary strings.
Data type
Thus far, we worked only with two data types: strings and integers (or—more precisely—32-bit integers). PowerShell supports many other data types, such as floating point numbers, strings, and Boolean values. You don’t have to explicitly declare the data type of a variable; PowerShell automatically chooses the data type for you when you initialize the variable—that is, when you first assign a value.
However, in some cases, PowerShell will not use the data type you intended, as the example below demonstrates:
$Number = Read-Host "Please enter a number" $Square=$Number*$Number Write-Host "The square of the number $Number is $Square."
If you didn’t sleep in math class, the result of this calculation should be a bit of a surprise. PowerShell wrongly assumed that the data type of the variable $Number is String. Because the arithmetic operator * is overloaded (the implementation of the operator depends on the arguments), the second line in the program multiplies a string instead of a number.
The second argument of the operator * always has to be a number, so PowerShell automatically converts the data type of $Number into Int32. However, the first argument can also be a string. The result is that PowerShell determines the value of the expression “2”*2, which is 22 (the string “2” is repeated two times).
Not only does PowerShell automatically assign a data type when you initialize the variable, but the data type can also change on the fly when the original data type doesn’t fit with the operation. In the example above, PowerShell needs a number for the operator *; because the string “2” looks very much like a number, it just converts it to the integer 2.
However, if no reasonable way exists to automatically convert the data type, and the data type doesn’t fit with the operation, PowerShell will throw an error. For instance, the lines below will produce the error message “Cannot convert value ‘b’ to type ‘System.Int32.’”
$a = "a" $b = "b" $a*$b
However, the next example, which looks very similar, runs through:
$a = "a" $b = "2" $a*$b
It is important to note that automatic conversion does not change the variable’s data type. Even though the value of the variable $b in the example has been used as an integer in the calculation, its data type is still String. To determine the type of a variable, you can use the GetType() method:
$b.GetType().Name
If it surprises you that the variable is equipped with a method, you’ll have to wait for a follow-up post where I will uncover the secret behind the command above.
We don’t have to rely on PowerShell’s ability to automatically convert data types if we tell the interpreter that we are expecting a number as input. This ensures that our script works as intended:
[Int]$Number = Read-Host "Please enter a number" $Square=$Number*$Number Write-Host "The square of the number $Number is $Square."
In the code snippet above, we explicitly declared the number as Int32 (integer) by enclosing the type name in square brackets before the variable name. A variable is called “weakly typed” if you only declare its data type implicitly by assigning a value of a certain type. If you declare the variable’s data type explicitly in your script, the variable is strongly typed.
As the example above shows, explicitly declaring variable types can prevent unwanted results in your scripts and makes them more reliable. However, this is not the only reason it makes sense to work with strongly typed variables. The things you can do with the value of a variable often depend on its data type.
For instance, you can store a certain date in a variable of the data type String, and you can use the data type DateTime that is intended for the purpose. As long as you only want to display the date, it makes no difference which data type you use. However, if you want to use the variable in calculations, you have to declare it as DateTime.
Let’s say you imported dates from a log file and you want to know how many days passed between a certain date and today’s date:
[DateTime]$Date = "February 28, 2015" $Today = Get-Date $Days = ($Today - $Date).Days Write-Host "The hacker encrypted all your servers $Days day(s) ago."
If you omit the declaration of the data type in the example above, PowerShell will politely inform you in a red-colored message that something went wrong: “Multiple ambiguous overloads found for…” Yes, the - operator is also overloaded.
Below is a list of some commonly used data types:
Data Type Name | Description |
[Array] | Array |
[Bool] | Value is TRUE or FALSE |
[DateTime] | Date and time |
[Guid] | Globally unique 32-byte identifier |
[HashTable] | Hash table, collection of key-value pairs |
[Int32], [Int] | 32-bit integers |
[PsObject] | PowerShell object |
[Regex] | Regular expression |
[ScriptBlock] | PowerShell script block |
[Single], [Float] | Floating point number |
[String] | String |
[Switch] | PowerShell switch parameter |
[TimeSpan] | Time interval |
[XmlDocument] | XML document |
In my next post, I will cover the variable scope.
Thanks, great article, I have compile the extended list of allowed datatypes in PowerShell:
1. [int] or [int32] 32-bit signed integer
2. [long] 64-bit signed integer
3. [char] Unicode 16-bit character
4. [string] Fixed-length string of Unicode characters
5. [single] or [float] Single-precision 32-bit floating point number
6. [double] Double-precision 64-bit floating point number
7. [decimal] 128-bit decimal value
8. [bool] True/false value
9. [byte] 8-bit unsigned integer
10. [array] Array of values
11. [hashtable] Hashtable object (similar to a Dictionary object)
12. [xml] or [XmlDocument] Xmldocument object
13. [DateTime] Date & time object.
14. [TimeSpan] Time interval.
15. [PsObject] PowerShell object.
16. [Switch] PowerShell Switch parameter.
17. [SctiptBlock] PowerShell Script object.
18. [RegEx] Regular expression.
19. [GUID] Globally unique 32-byte identifier.
Thanks! That’s quite a lot.
Hello,
Thanks for the article!
Could I ask something?:
If I declare:
[int]$var = “2”
Would it take it as an integer or as a string? . Because with “int” you are forcing it to be a number, but with the double quotes , would it take it as a string?
I am unsure, thanks
@Luis
It doesn’t matter if you use single or double quotes or noting. The type is enforced by the content between the brackets.
Many thanks Luc.
Michael,
Are there any down-sides to always using strongly typed variables in PowerShell (when initializing the variable, force the data type with the [<data type>] data type)?
From a security standpoint, are there any possible reasons we would always use strongly typed variables? I worry about a scenario like the following example code:
Obviously, this example is not a PoC, albeit it should (hopefully) convey my question in a more understandable way, if the worded question wasn't 100% clear.
In my example code, the PowerShell interpreter parses the script. It reads the main function, it makes its way down to our entry-point, it comes across the call the main function, it executes the main function, it asks the user for their age, however, the user types a crafted string that is a command that gets executed when the Write-Output function is printed the users age.
Does that make sense? If so, is such a scenario possible with weakly typed variables vs strongly typed variables? Finally, is there ever a time we would want to use weakly typed variables? My understanding (please correct me if I'm wrong), we can type cast a variable if we need to. So for the most part, strongly typed variables, if I am understanding everything correctly, should always be used, right?
Thanks!
Whatever the user enter will never be executed with Write-Output command, it will be simply displayed.
@Leos Marek,
Just so I am understanding you correctly, are you saying Write-Output is not exploitable in any way? I remember with an old device called an Archos, there was a field where you could type some sort of text which would set a setting for the Archos. Someone found a way to exploit that by tricking the software on the Archos to think that the actual user data entered was over with and then a php command was supposed to be run.
I just wanted to make certain we didn't have to parse the user data to make sure there is no types of injection or anything like that.
Thank you!!!!!
Hi Kenneth,
its not about Write-Output or any other command. It is about what Powershell allows you to execute. You can only execute things in certain way. Example below, I need to create a variable which is a Scriptblock type.
While with Read-host, the variable will always be only a string.
So its only text, nothing else. You cant execute text.
So, this is safe 🙂
Actually, you can execute strings in PowerShell. Try this:
And Kenneth, everything that is stored in a computer's memory is exploitable. This also applies to Write-Output. The only question how easy it is to exploit certain commands.
Michael,
sorry I dont get the point. This will only write the text, as expected.
Exactly. If you execute a string on a PowerShell console, PowerShell takes the string and prints it on the screen. Try this on a Command Prompt and you will get an error message because this shell doesn't know how to execute strings.
Or try this to better understand what is actually happening:
When you are dealing with strings, you have to be particularly careful because hackers love to execute code in strings. This is why we need to sanitize strings in many cases.
Of course, this is clear as day. That is different thing – enumerating variables in string.
But you will not achieve this in the case Kenneth asked:
Same as if I type
I will receive the string, not the actual output of Get-date. So from this perspective, I don't see a way how a user executing script provided by his IT department could inject his code by Read-Host.
I wasn't replying to Kenneth, but to your claim that text can't be executed.
And Read-Host doesn't always safe you. Just because you enter a string, does not guarantee that your input cannot be executed:
And I think Kenneth's original question was if strongly typed variables improve security. In general, I would say yes, but in the case of PowerShell strings, it doesn't really matter because PowerShell executes strongly typed string variables anyway.
Okay, seems like a wording issue here.
On one side you are right. What you showed can be done, but that has to be already badly coded in the script.
But, the query was about exploting this by user
Which I dont think its possible, the input will be always a string, no matter what, and cannot be executed this way.
I think this is not a real world script. It is just an example how a string can get executed in PowerShell. I guess Kenneth asked a general question and that is if strong typing improves security in the case of user input and I would say no because Read-Host sets the type to string anyway.
If you allow users to input text, you always have to be extra careful with what you do with those strings. The type of the input variable doesn't really matter that much. There are a myriad of ways how attackers can execute input strings.
For what it is worth, you can take the input from read-host and as long as you type your receiving variable, and the input can be coerced to the correct type, that's what you will receive.