As the name implies, Microsoft PowerShell is a powerful command shell and scripting language. It provides convenient access to the .NET framework along with many other useful features. These pages will help you use Perforce and PowerShell together.
See Windows PowerShell in Action if you would like to learn more about PowerShell in general.
You can use environment variables to configure Perforce. Environment variables always begin with $env: in PowerShell.
PowerShell supports a rich set of types, not just strings as in other command shells. Further, because of the way PowerShell parses the right side of assignments, literal strings must be quoted when they appear in that position.
For example, the IP address and port number in the following example must be quoted. Otherwise, PowerShell would try to parse the right side of the assignment as a number. It would parse 192.168 and a number but will then be unable to parse the .0.
PS D:\workspaces\alamimo_ws> $env:P4PORT="192.168.0.2:1666"
Without the quotes, you would have seen this.
Unexpected token '.0' in expression or statement. At line:1 char:22 + $env:P4PORT=192.168.0. <<<< 2:1666
Quotes are also required around the user name in the following example to prevent PowerShell from interpreting it as a command (because of its position on the right side of an assignment).
PS D:\workspaces\alamimo_ws> $env:P4USER="alamimo"
Without the quotes, you would have seen this.
The term 'alamimo' is not recognized as a cmdlet, function, operable program, or script file. Verify the term and try again. At line:1 char:19 + $env:P4USER=alamimo <<<<
Note, you do not need special quoting when using p4 set because PowerShell passes the arguments as string literals to the p4 command.
PS D:\workspaces\alamimo_ws> p4 set P4CONFIG=P4CONFIG
Works as it does in the XP command interpreter (cmd.exe).
To learn more about how PowerShell parses commands, enter the following at the PowerShell prompt
PS D:\workspaces\alamimo_ws> help about_parsing
To learn more about environment variables, enter the following at the PowerShell prompt
PS D:\workspaces\alamimo_ws> help about_environment_variable
Unlike the XP command interpreter (cmd.exe), double quotes are not sufficient to prevent the wildcard character (*) from being expanded on the client when using PowerShell. You need to provide extra quotes to prevent PowerShell from evaluating away the double quotes.
The extra quoting can be supplied as single quotes surrounding the double quotes or by escaping the double quotes with grave-accent characters.
For example,
PS D:\workspaces\alamimo_ws> p4 files '"*"'
or
PS D:\workspaces\alamimo_ws> p4 files `"*`"
will pass the command line to p4 in the same way as the XP command interpreter.
You can use the following program to test your quoting and examine what would be passed to p4.
/* gcl.c, Get and print the command line. * This program can be used to deterime how cmd.exe and PowerShell parsing differ. * * To build: * cl gcl.c /link kernel32.lib */ #include "Windows.h" main() { printf("%s\n", GetCommandLine()); }view plain text source
XP command interpreter (cmd.exe)
The example below illustrates that the XP command interpreter passes the command line to the program without modification.
D:\projects\gcl>.\gcl * .\gcl * D:\projects\gcl>.\gcl "*" .\gcl "*"
PowerShell
Notice that in the first two examples below the wildcard character is passed to the program without double quotes. The last two examples show that the extra quoting produces the desired result.
PS D:\projects\gcl> .\gcl * "D:\projects\gcl\gcl.exe" * PS D:\projects\gcl> .\gcl "*" "D:\projects\gcl\gcl.exe" * PS D:\projects\gcl> .\gcl '"*"' "D:\projects\gcl\gcl.exe" "*" PS D:\projects\gcl> .\gcl `"*`" "D:\projects\gcl\gcl.exe" "*"
To learn more about quoting, enter the following at the PowerShell prompt
PS D:\workspaces\alamimo_ws> help about_quoting_rules
The PowerShell comment character is #. Care must be taken when using it with Perforce as a revision specifier. This command
PS D:\workspaces> p4 sync #0
Would be interpreted as:
PS D:\workspaces> p4 sync
That is, everything starting with # would be interpreted as a comment and ignored. You could use any of the following to achieve the desired result.
PS D:\workspaces> p4 sync "#0" PS D:\workspaces> p4 sync '#0' PS D:\workspaces> p4 sync `#0
The # character is not interpreted as a comment character when embedded in a string. For example,
PS D:\workspaces> p4 sync myfile#0
would be interpreted literally. The # is not interpreted as a comment character because it is embedded in a string.
The PowerShell array subexpression character (@) is also used in Perforce revision specifications. There is no ambiguity when this character is embedded in another string. For example,
PS D:\workspaces> p4 files //....@2
is passed to p4 as desired.
A problem arises when the @ character is the first character of a token. For example,
PS D:\workspaces> p4 files @2,@4
results in:
Unrecognized token in source text. At line:1 char:10 + p4 files @ <<<< 2,@4
This is because PowerShell attempts to parse the characters following the @ as an array subexpression.
This can be easily addressed by quoting the @ characters. For example,
PS D:\workspaces> p4 files `@2,`@4 PS D:\workspaces> p4 files "@2,@4" PS D:\workspaces> p4 files '@2,@4'
all work as desired.
PowerShell enables the output of one command to be piped into the input of another (much like Unix command shells) PowerShell provides operators and Cmdlets that can be used to filter pipeline data.
Perforce Command Line Recipes, in the Public Depot Wiki, contains Unix pipeline examples. I've add their PowerShell equivalents.
The first column following table lists Unix commands commonly used in pipelines. The second column lists their PowerShell counterparts along with PowerShell examples.
| Unix Command | PowerShell Command |
|---|---|
| grep |
Select-String p4 changes -m100 | select-string 'pkania' |
| grep -v |
Where-Object{$_ -notmatch RE} ?{$_ -notmatch RE} p4 files ... | ?{$_ -notmatch 'change \d+ \(binary'} lists all the Perforce files under the current directory that aren't binary |
| sed |
ForEach-Object{$_ -replace RE,EXPR} %{$_ -replace RE,EXPR} p4 changes -ssubmitted -m10 | %{$_ -replace '^Change (\d+).*','$1'} lists the change numbers of the last 10 submitted changelists |
| backquote (``) |
$() $(p4 changes -m1 -ssubmitted).split()[1] evaluates to the number of the last submitted changelist $(p4 label -o pkania-saved-tag) -replace "Created by pkania","Phil's saved work" | p4 label -i retrieves the label form, replaces the description and save the changes This idiom is commonly used to update Perforce forms. Double quotes are used around the expressions above because of the embedded single quote. $(p4 change -o) -replace '<enter description here>','Nightly build results' | p4 submit -i See KB Article: Submitting Files Non-interactively |
| xargs |
ForEach-Object{} %{} p4 changes -ssubmitted '@2009/01/08,@2009/01/09' | %{p4 describe $_.split()[1]} describes all the changes that were submitted on 1/8/2009 |
| find . -type f |
Get-ChildItem gci gci -recurse | ?{-not $_.PSIsContainer} | %{$_.FullName} |
| head |
Select-Object -first n select -first n p4 files ....cs | select -first 10 |
| tail |
Select-Object -last n select -last n p4 files ....cs | select -last 10 |
The Select-String Cmdlet filters its input for strings matching the supplied regular expression much like the Unix grep command.
The -match and -notmatch operators, used with the Where-Object Cmdlet (whose alias is ?), can also be used to filter the pipeline.
The automatic variable $_ contains the current pipeline object in the Where-Object and ForEach-Object script blocks.
The -replace operator, used with the ForEach-Object Cmdlet (whose alias is %), can be used to replace text matching the specified regular expression, much like the Unix sed command.
It's a good idea to get in the habit of quoting regular expression patterns with single quotes ('') instead of double quotes (""). If you use double quotes, PowerShell will attempt to expand and backreferences (e.g '^Change (\d+).*','$1') before passing the pattern to the operators or Cmdlets.
They subexpression operator $() can be used to substitute the output of another command (or pipeline) into a place where an expression is expected. It can be used much like the backquoting (``) characters are used in Unix command shells.
The ForEach-Object Cmdlet can also be used like the Unix xargs command to repeatedly execute a command with arguments from the pipeline.
gci, the alias for the Get-ChildItem Cmdlet, with the -recurse option can can be used to find files much like the Unix find command. You can supply arguments to Get-ChildItem to filter the returned items.
PowerShell strings inherit the methods of the .NET String class. You access these with the dot operator. For example:
PS D:\workspaces\alamimo_ws> $upper = "Mixed Case".ToUpper()
Pattern strings can be cast to regular expression objects. PowerShell regular expression objects inherit the methods of the .NET Regex class.For example:
PS D:\workspaces\alamimo_ws> $re = [regex]'\s+'
PS D:\workspaces\alamimo_ws> $re.Split("one two three")
You can also access static methods of .NET classes from within PowerShell. The .NET Regex class provides a static Split method that can split a string using a regular expression. For example:
PS D:\workspaces\alamimo_ws> $words = [regex]::Split("this is a sentence",'\s+')The Select-Object Cmdlet can also be used like the Unix head and tail commands. It can also be used to construct objects in the pipeline.
To learn more about the Select-String Cmdlet, enter the following at the PowerShell prompt
PS D:\workspaces\alamimo_ws> help Select-String
To learn more about the regular expressions, enter the following at the PowerShell prompt
PS D:\workspaces\alamimo_ws> help about_regular_expression
To learn more about the -match, -notmatch and -replace operators enter the following at the PowerShell prompt
PS D:\workspaces\alamimo_ws> help about_comparison_operators
To learn more about the ForEach-Object Cmdlet, enter the following at the PowerShell prompt
PS D:\workspaces\alamimo_ws> help ForEach-Object
To learn more about the Where-Object Cmdlet, enter the following at the PowerShell prompt
PS D:\workspaces\alamimo_ws> help Where-Object
To learn more about the GetChild-Item Cmdlet, enter the following at the PowerShell prompt
PS D:\workspaces\alamimo_ws> help GetChild-Item
To learn more about the Select-Object Cmdlet, enter the following at the PowerShell prompt
PS D:\workspaces\alamimo_ws> help Select-Object