PowerShell distinguishes sharply between text in single quotation marks and text in double quotation marks. PowerShell won't modify text wrapped in single quotation marks but it does inspect text in single quotation marks and may modify it by inserting variable contents automatically. Enclosing text in double quotation marks is the foremost and easiest way to couple results and descriptions. The formatting operator -f, one of many specialized string operators, offers more options. For example, you can use -f to output text column-by-column and to set it flush. Other string commands are also important. They can replace selected text, change case, and much more. Pattern recognition adds a layer of complexity because it uses wildcard characters to match patterns. In simple cases, you can use the same wildcards that you use in the file system. Substantially more powerful, but also more complex, are regular expressions. Topics Covered:
Defining TextUse quotation marks to delimit it if you'd like to save text in a variable or to output it. Use single quotation marks if you want text to be stored in a variable in (literally) exactly the same way you specified it: $text = 'This text may also contain $env:windir `: $(2+2)'
This text may also contain $env:windir `: $(2+2)
Text will have an entirely different character when you wrap it in (conventional) double quotation marks because enclosed special characters will be evaluated: $text = "This text may also contain $env:windir `: $(2+2)"
This text may also contain C:\Windows: 4
Special Characters in TextIf text is enclosed in double quotation marks, PowerShell will look for particular special characters in it. Two special characters are important in this regard: "$" and the special backtick character, "`". Resolving VariablesIf PowerShell encounters one of the variables from Chapter 3, it will assign the variable its value: $windir = "The Windows directory is here: $env:windir"
$windir The Windows directory is here: C:\Windows
This also applies to direct variables, which calculate their value themselves: $result = "One CD has the capacity of $(720MB / 1.44MB) diskettes."
$result One CD has the capacity of 500 diskettes.
Inserting Special CharactersThe peculiar backtick character, "`", has two tasks: if you type it before characters that are particularly important for PowerShell, such as "$" or quotation marks, PowerShell will interpret the characters following the backtick as normal text characters. You could output quotation marks in text like this: "This text includes `" quotation marks`""
This text includes "quotation marks"
If one of the letters listed in Table 13.1 follows the backtick character, PowerShell will insert special characters: $text = "This text consists of`ntwo lines."
This text consists of
two lines!
Table 13.1: Special characters and "escape" sequences for text "Here-Strings": Acquiring Text of Several LinesUsing "here-strings" is the best way to acquire long text consisting of several lines or many special characters. "Here-strings" are called by this name because they enable you to acquire text exactly the way you want to store it in a text variable, much like a text editor. Here-strings are preceded by the @" character and terminated by the "@ character. Note here once again that PowerShell will automatically resolve (assign variable values and evaluate backtick characters in) text enclosed by @" and "@ characters. If you use single quotation marks instead, the text will remain exactly the way you typed it: $text = @"
Here-Strings can easily stretch over several lines and may also include "quotation marks". Nevertheless, here, too, variables are replaced with their values: C:\Windows, and subexpressions like 4 are likewise replaced with their result. The text will be concluded only if you terminate the here-string with the termination symbol "@. "@ $text Here-Strings can easily stretch over several lines and may also include
"quotation marks". Nevertheless, here, too, variables are replaced with their values: C:\Windows, and subexpressions like 4 are likewise replaced with their result. The text will be concluded only if you terminate the here-string with the termination symbol "@. Communicating with the UserIf you'd like to request users to input text, use Read-Host: $text = Read-Host "Your entry"
Your entry: Hello world! $text Hello world!
Text acquired by Read-Host behaves like text enclosed in single quotation marks. Consequently, special characters and variables are not resolved. Manually use the ExpandString() method if you want to resolve the contents of a text variable later on, that is, have the variables and special characters in it replaced. PowerShell normally uses this method internally when you allocate text in double quotation marks: # Query and output text entry by user:
$text = Read-Host "Your entry" Your entry: $env:windir $text $env:windir
# Treat entered text as if it were in double quotation marks: $ExecutionContext.InvokeCommand.ExpandString($text) $text C:\Windows
If you'd like to use Read-Host to acquire sensitive data, passwords, use the -asSecureString parameter. The screen entries will be masked by asterisks. The result will be a so-called SecureString. To be able to work on the encrypted SecureString as a normal text entry, it must be changed to plain text first: $pwd = Read-Host -asSecureString "Password"
Password: *************
$pwd
System.Security.SecureString
[Runtime.InteropServices.Marshal]::`
PtrToStringAuto([Runtime.InteropServices.Marshal]::` SecureStringToBSTR($pwd)) strictly confidential
Querying User Name and PasswordIf you'd like to authenticate a user, such as query his name and password, use Get-Credential. This cmdlet uses the secure dialog boxes that are integrated into Windows to request user name and password: Get-Credential -Credential "Your name?"
UserName Password
-------- -------- \Your name System.Security.SecureString The result is an object having two properties: the given user name is in UserName and the encrypted password is in Password as an instance of SecureString: Normally, Get-Credential is used if logon data are actually needed, such as to run a program under a particular user name: $logon = Get-Credential
$startinfo = new-object System.Diagnostics.ProcessStartInfo $startinfo.UserName = $logon.UserName $startinfo.Password = $logon.Password $startinfo.FileName = "$env:windir\regedit.exe" $startinfo.UseShellExecute = $false [System.Diagnostics.Process]::Start($startinfo) However, the user context that creates the Secure String can turn it into readable text whenever you wish, as was the case for Read-Host. For this reason, you can also use Get-Credential to query sensitive information that you can work on subsequently in plain text: $logon = Get-Credential
[Runtime.InteropServices.Marshal]::` PtrToStringAuto([Runtime.InteropServices.Marshal]::` SecureStringToBSTR($logon.Password)) MySecretPassword
Using Special Text CommandsOften, results need to be properly output and provided with descriptions. The simplest approach doesn't require any special commands: insert the result as a variable or sub-expression directly into text and make sure that text is enclosed in double quotation marks. # Embedding a subexpression in text:
"One CD has the capacity of $(720MB / 1.44MB) diskettes." One CD has the capacity of 500 diskettes.
# Embedding a variable in text: $result = 720MB / 1.44MB "One CD has the capacity of $result diskettes." One CD has the capacity of 500 diskettes.
More options are offered by special text commands that PowerShell furnishes from three different areas:
String OperatorsThe -f format operator is the most important PowerShell string operator. You'll soon be using it to format numeric values for easier reading: "{0} diskettes per CD" -f (720mb/1.44mb)
500 diskettes per CD
All operators function in basically the same way: they anticipate data from the left and the right that they can link together. For example, you can use -replace to substitute parts of the string for other parts: "Hello Carl" -replace "Carl", "Eddie"
Hello Eddie
There are three implementations of the -replace operator; many other string operators also have three implementations. Its basic version is case insensitive. If you'd like to distinguish between lowercase and uppercase, use the version beginning with "c" (for case-sensitive): # No replacement because case sensitivity was turned off this time:
"Hello Carl" -creplace "carl", "eddie" Hello Carl
The third type begins with "i" (for insensitive) and is case insensitive. This means that this version is actually superfluous because it works the same way as -replace. The third version is merely demonstrative: if you use -ireplace instead of -replace, you'll make clear that you expressly do not want to distinguish between uppercase and lowercase.
Table 13.2: Operators used for handling string Formatting StringThe format operator -f formats a string and requires a string, along with wildcards on its left side and on its right side, that the results are to be inserted into the string instead of the wildcards: "{0} diskettes per CD" -f (720mb/1.44mb)
500 diskettes per CD
It is absolutely necessary that exactly the same results are on the right side that are to be used in the string are also on the left side. If you want to just calculate a result, then the calculation should be in parentheses. As is generally true in PowerShell, the parentheses ensure that the enclosed statement is evaluated first and separately and that subsequently, the result is processed instead of the parentheses. Without parentheses, -f would report an error: "{0} diskettes per CD" -f 720mb/1.44mb
Bad numeric constant: 754974720 diskettes per CD.
At line:1 char:33 + "{0} diskettes per CD" -f 720mb/1 <<<< .44mb You may use as many wildcard characters as you wish. The number in the braces states which value will appear later in the wildcard and in which order: "{0} {3} at {2}MB fit into one CD at {1}MB" `
-f (720mb/1.44mb), 720, 1.44, "diskettes" 500 diskettes at 1.44MB fit into one CD at 720MB
Setting Numeric FormatsThe formatting operator -f can insert values into text as well as format the values. Every wildcard used has the following formal structure: {index[,alignment][:format]}:
Formatting statements are case sensitive in different ways than what is usual in PowerShell. You can see how large the differences can be when you format dates: # Formatting with a small letter d:
"Date: {0:d}" -f (Get-Date) Date: 08/28/2007
# Formatting with a large letter D:
"Date: {0:D}" -f (Get-Date) Date: Tuesday, August 28, 2007
Table 13.3: Formatting numbers Using the formats in Table 13.3, you can format numbers quickly and comfortably. No need for you to squint your eyes any longer trying to decipher whether a number is a million or 10 million: 10000000000
"{0:N0}" -f 10000000000 10,000,000,000 There's also a very wide range of time and date formats. The relevant formats are listed in Table 13.4 and their operation is shown in the following lines: $date= Get-Date
Foreach ($format in "d","D","f","F","g","G","m","r","s","t","T", ` "u","U","y","dddd, MMMM dd yyyy","M/yy","dd-MM-yy") { "DATE with $format : {0}" -f $date.ToString($format) } DATE with d : 10/15/2007
DATE with D : Monday, 15 October, 2007 DATE with f : Monday, 15 October, 2007 02:17 PM DATE with F : Monday, 15 October, 2007 02:17:02 PM DATE with g : 10/15/2007 02:17 DATE with G : 10/15/2007 02:17:02 DATE with m : October 15 DATE with r : Mon, 15 Oct 2007 02:17:02 GMT DATE with s : 2007-10-15T02:17:02 DATE with t : 02:17 PM DATE with T : 02:17:02 PM DATE with u : 2007-10-15 02:17:02Z DATE with U : Monday, 15 October, 2007 00:17:02 DATE with y : October, 2007 DATE with dddd, MMMM dd yyyy : Monday, October 15 2007 DATE with M/yy : 10/07 DATE with dd-MM-yy : 15-10-07
Table 13.4: Formatting date values If you want to find out which type of formatting options are supported, you need only look for .NET types that support the toString() method: [appdomain]::currentdomain.getassemblies() | ForEach-Object {
$_.GetExportedTypes() | Where-Object {! $_.IsSubclassof([System.Enum])} } | ForEach-Object { $Methods = $_.getmethods() | Where-Object {$_.name -eq "tostring"} |%{"$_"}; If ($methods -eq "System.String ToString(System.String)") { $_.fullname } } System.Enum
System.DateTime System.Byte System.Convert System.Decimal System.Double System.Guid System.Int16 System.Int32 System.Int64 System.IntPtr System.SByte System.Single System.UInt16 System.UInt32 System.UInt64 Microsoft.PowerShell.Commands.MatchInfo For example, among the supported data types is the "globally unique identifier" System.Guid. Because you'll frequently require GUID, which is clearly understood worldwide, here's a brief example showing how to create and format a GUID: $guid = [GUID]::NewGUID()
Foreach ($format in "N","D","B","P") { "GUID with $format : {0}" -f $GUID.ToString($format)} GUID with N : 0c4d2c4c8af84d198b698e57c1aee780
GUID with D : 0c4d2c4c-8af8-4d19-8b69-8e57c1aee780 GUID with B : {0c4d2c4c-8af8-4d19-8b69-8e57c1aee780} GUID with P : (0c4d2c4c-8af8-4d19-8b69-8e57c1aee780)
Table 13.5: Customized date value formats Outputting Values in Tabular Form: Fixed WidthTo display the output of several lines in a fixed-width font and align them one below the other, each column of the output must have a fixed width. A formatting operator can set outputs to a fixed width. In the following example, Dir returns a directory listing, from which a subsequent loop outputs file names and file sizes. Because file names and sizes vary, the result is ragged right and hard to read: dir | ForEach-Object { "$($_.name) = $($_.Length) Bytes" }
history.csv = 307 Bytes
info.txt = 8562 Bytes layout.lxy = 1280 Bytes list.txt = 164186 Bytes p1.nrproj = 5808 Bytes ping.bat = 116 Bytes SilentlyContinue = 0 Bytes The following result with fixed column widths is far more legible. To set widths, add a comma to the sequential number of the wildcard and after it specify the number of characters available to the wildcard. Positive numbers will set values to right alignment, negative numbers to left alignment: dir | ForEach-Object { "{0,-20} = {1,10} Bytes" -f $_.name, $_.Length }
history.csv = 307 Bytes
info.txt = 8562 Bytes layout.lxy = 1280 Bytes list.txt = 164186 Bytes p1.nrproj = 5808 Bytes ping.bat = 116 Bytes SilentlyContinue = 0 Bytes String Object MethodsYou know from Chapter 6 that PowerShell stores everything in objects and that every object contains a set of instructions known as methods. Text is stored in a String object, which includes a number of useful commands for working with text. For example, to ascertain the file extension of a file name, use LastIndexOf() to determine the position of the last "." character, and then use Substring() to extract text starting from the position: $path = "c:\test\Example.bat"
$path.Substring( $path.LastIndexOf(".")+1 ) bat
Another approach uses the dot as separator and Split() to split up the path into an array. The result is that the last element of the array (-1 index number) will include the file extension: $path.Split(".")[-1]
bat
Table 13.6 provides an overview of all the methods that include a string object.
Table 13.6: The methods of a string object Analyzing Methods: Split() as ExampleYou already know in detail from Chapter 6 how to use Get-Member to find out which methods an object contains and how to invoke them. Just as a quick refresher, let's look again at an example of the Split() method to see how it works. ("something" | Get-Member Split).definition
System.String[] Split(Params Char[] separator), System.String[] Split(
Char[] separator, Int32 count), System.String[] Split(Char[] separator, StringSplitOptions options), System.String[] Split(Char[] separator, Int32 count, StringSplitOptions options), System.String[] Split(String[] separator, StringSplitOptions options), System.String[] Split(String[] separator, Int32 count, StringSplitOptions options) Definition gets output, but it isn't very easy to read. Because Definition is also a string object, you can use methods from Table 13.6, including Replace(), to insert a line break where appropriate. That makes the result much more understandable: ("something" | Get-Member Split).Definition.Replace("), ", ")`n")
System.String[] Split(Params Char[] separator)
System.String[] Split(Char[] separator, Int32 count) System.String[] Split(Char[] separator, StringSplitOptions options) System.String[] Split(Char[] separator, Int32 count, StringSplitOptions options) System.String[] Split(String[] separator, StringSplitOptions options) System.String[] Split(String[] separator, Int32 count, StringSplitOptions options) There are six different ways to invoke Split(). In simple cases, you might use Split() with only one argument, Split(), you will expect a character array and will use every single character as a possible splitting separator. That's important because it means that you may use several separators at once: "a,b;c,d;e;f".Split(",;")
a
b c d e f If the splitting separator itself consists of several characters, then it has got to be a string and not a single Char character. There are only two signatures that meet this condition: System.String[] Split(String[] separator,
StringSplitOptions options) System.String[] Split(String[] separator, Int32 count, StringSplitOptions options) You must make sure that you pass data types to the signature that is exactly right for it to be able to use a particular signature. If you want to use the first signature, the first argument must be of the String[] type and the second argument of the StringSplitOptions type. The simplest way for you to meet this requirement is by assigning arguments first to a strongly typed variable. Create the variable with exactly the type that the signature requires: # Create a variable of the [StringSplitOptions] type:
[StringSplitOptions]$option = "None" # Create a variable of the String[] type: [string[]]$separator = ",;" # Invoke Split with the wished signature and use a two-character long separator: ("a,b;c,;d,e;f,;g").Split($separator, $option) a,b;c
d,e;f g Split() in fact now uses a separator consisting of several characters. It splits the string only at the points where it finds precisely the characters that were specified. There does remain the question of how do you know it is necessary to assign the value "None" to the StringSplitOptions data type. The simple answer is: you don't know and it isn't necessary to know. If you assign a value to an unknown data type that can't handle the value, the data type will automatically notify you of all valid values: [StringSplitOptions]$option = "werner wallbach"
Cannot convert value "werner wallbach" to type
"System.StringSplitOptions" due to invalid enumeration values. Specify one of the following enumeration values and try again. The possible enumeration values are "None, RemoveEmptyEntries". At line:1 char:28 + [StringSplitOptions]$option <<<< = "werner wallbach" By now it should be clear to you what the purpose is of the given valid values and their names. For example, what was RemoveEmptyEntries() able to accomplish? If Split() runs into several separators following each other, empty array elements will be the consequence. RemoveEmptyEntries() deletes such empty entries. You could use it to remove redundant blank characters from a text: [StringSplitOptions]$option = "RemoveEmptyEntries"
"This text has too much whitespace".Split(" ", $option) This
text has too much whitespace Now all you need is just a method that can convert the elements of an array back into text. The method is called Join(); it is not in a String object but in the String class. Using String Class CommandsChapter 6 clearly defined the distinction between classes and objects (or instances). Just to refresh your memory: every String object is derived from the String class. Both include diverse methods. You can see these methods at work when you press (Tab) after the following instruction, which activates AutoComplete: [String]::(Tab)
Get-Member will return a list of all methods. This time, specify the -Static parameter in addition: "sometext" | Get-Member -Static -MemberType Method
You've already used static methods. In reality, the -f format operator corresponds to the Format() static method, and that's why the following two statements work in exactly the same way: # Using a format operator:
"Hex value of 180 is &h{0:X}" -f 180 Hex value of 180 is &hB4
# The static method Format has the same result: [string]::Format("Hex value of 180 is &h{0:X}", 180) Hex value of 180 is &hB4
The Format() static method is very important but is usually ignored because -f is much easier to handle. But you wouldn't be able to do without two other static methods: Join() and Concat(). Join(): Changing Arrays to TextJoin() is the counterpart of Split() discussed above. Join() assembles an array of string elements into a string. It enables you to complete the above example and to make a function that removes superfluous white space characters from the string: function RemoveSpace([string]$text) {
$private:array = $text.Split(" ", ` [StringSplitOptions]::RemoveEmptyEntries) [string]::Join(" ", $array) } RemoveSpace "Hello, this text has too much whitespace." Hello, this text has too much whitespace.
Concat(): Assembling a String Out of Several PartsConcat() assembles a string out of several separate parts. At first glance, it works like the "+" operator: "Hello" + " " + "World!"
Hello World!
But note that the "+" operator always acts strangely when the first value isn't a string: # Everything will be fine if the first value is string:
"Today is " + (Get-Date) Today is 08/29/2007 11:02:24
# If the first value is not text, errors may result: (Get-Date) + " is a great date!" Cannot convert argument "1", with value: " is a great date!",
for "op_Addition" to type "System.TimeSpan": "Cannot convert value " is a great date!" to type "System.TimeSpan". Error: "Input string was not in a correct format."" At line:1 char:13 + (Get-Date) + <<<< " is a great date! If the first value of the calculation is a string, all other values will be put into the string form and assembled as requested into a complete string. If the first value is not a string—in the example, it was a date value—all the other values will be changed to this type. That's just what causes an error, because it is impossible to change "is a great date!" to a date value. For this reason, the "+" operator is an unreliable tool for assembling a string. Concat() causes fewer problems: it turns everything you specify to the method into a string. Concat(), when converting, also takes into account your current regional settings; it will provide, for example, U.S. English date and time formats: [string]::Concat("Today is ", (Get-Date))
Today is 8/29/2007 11:06:00 AM
[string]::Concat((Get-Date), " is a great date!") 8/29/2007 11:06:24 AM is a great date!
Simple Pattern RecognitionRecognizing patterns is a frequent task that is necessary for verifying user entries, such as to determine whether a user has given a valid network ID or valid e-mail address. Useful and effective pattern recognition requires wildcard characters that represent a certain number and type of characters. A simple form of wildcards was invented for the file system many years ago and it still works today. In fact, you've doubtlessly used it before in one form or another: # List all files in the current directory that
# have the txt file extension: Dir *.txt # List all files in the Windows directory that # begin with "n" or "w": dir $env:windir\[nw]*.* # List all files whose file extensions begin with # "t" and which are exactly 3 characters long: Dir *.t?? # List all files that end in one of the letters # from "e" to "z" dir *[e-z].* 手机版|小黑屋|BC Morning Website ( Best Deal Inc. 001 ) GMT-8, 2025-8-25 20:00 , Processed in 0.016436 second(s), 25 queries . Supported by Best Deal Online X3.5 © 2001-2025 Discuz! Team. |