Introduction
PowerShell is the better Command Prompt. It allows you to use any .Net functionality and access a lot of Windows' not-so-obvious functionality which were difficult to access with the CMD. PowerShell is based on .Net 2.0 and connects the philosophy of Pipes and Filters (known from Unix Shells) with the paradigm of object orientated programming.
The core of the PowerShell is based on small functionality units, called Cmdlets ("command-lets"). A list of the Cmdlets can be retrieved this Microsoft Technet page.
Background - Syntax
The syntax of the scripting language used for Powershell Scripts has its own syntax. This chapter gives you a brief overview over the syntax and removes some of the traps a PowerShell script hides in it.
Variables and Constants
#Variables are defined with a leading '$':
$programFilesX86 = (${env:ProgramFiles(x86)}, ${env:ProgramFiles} -ne $null)[0]
The above example sets the variable "programFilesX86" to the path of the program files folder for x86 programs. Because the folder doesn't exist on x86 platforms, the variable is set to the ordinary program files directory if the x86 folder isn't available.
#Constants are also defined with a leading '$' -
#To distinguish them from variables, they shall be written in all-capital letters.
$CONSTVAL = "This value can't be changed"
Set-Variable CONSTVAL -option ReadOnly
Even though not needed by interpreter specifications, I recommend you to write constants in all-capital letters to distinguish them from variables.
Functions
PowerShell script files are interpreted and if a method is called which isn't read by the interpreter before it is called, PowerShell will encounter an error. The best way to avoid this error trap is to define a method called "Main" at the top, and then define a jump to this very method at the end of the file:
function main{
#main function, as known from classic structured programs.
myFunction
}
function myFunction{
Write-Host "myFunction was called"
}
main #Jump to execute main
The example below is supposed to do the exact same, but will not be able to run because the function "myFunction" isn't interpreted at the time it is called.
myFunction #Error - myFunction wasn't read yet, but is already called
function myFunction{
Write-Host "myFunction was called" #will never be reached
}
Basic commands
File System
As the Command Prompt already did, PowerShell provides a vast amount of Cmdlets to access the file system and modify files and directories.
Copy a File
Files can be copied using the Copy-Item Cmdlet, where the first parameter specifies the source file and the second parameter specifies the source file's full path:
Copy-Item -Path "C:\Source\Powershell" -Destination "C:\Testumgebung"
The copy process can be made recursive by adding the -Recures parameter at the end of the command:
Copy-Item -Path "C:\Source\Powershell" -Destination "C:\Testumgebung" -Recurse
Get File or Folder information
File or folder information can be obtained using the Get-Item Cmdlet:
Get-Item -Path "C:\"
To get information about the child items of a path, you can either use Get-Item with an added wildcard or Get-ChildItem:
Get-Item -Path "C:\*"
Get-ChildItem -Path "C:\"
Both Cmdlets return details on the child items of C:\:
Remove a file or a directory
Remove-Item -Path "C:\Source\Test1\*.txt" -Recurse -Force
The -Recurse parameter can only be applied to files, while -Force also deletes locked files. In the above shown parametrization, any *.txt file will be removed from C:\Source\Test1 and its subfolders.
Copy a file or a directory
Copy-Item -Path "C:\Source\*.txt" -Destination "C:\Source\Textfiles" -Recurse
This command copies any *.txt file from C:\Source and its subfolders to C:\Source\Textfiles, and the sub folder structure remains unchanged.
Interaction with Processes
PowerShell provides a vast amount of Cmdlets to help you analyze and manipulate running processes.
You can start a new process with almost any possible option:
Start-Process powershell.exe
would start a new PowerShell instance. Start-Process is a mighty Cmdlet and does provide a lot of parameters. A list of all parameters can be found at this Microsoft Technet Homepage.
To get a list of all running processes on your system, you can use
Get-Process
This displays a list of all running processes, including some additional information:
Of course you can search for a very specific process by it's name:
Get-Process powershell
This behavior can be extended by searching for more than one process name, for example PowerShell and the Windows Explorer:
Get-Process powershell,explorer
You get the idea - Any number of process names can be checked that way. In case you are looking for a process which isn't running, PowerShell will return an error (e.g. throw). What you might haven't known yet is that the usage of wildcards is allowed for the process name, means that
Get-Process power*
will return every running process which starts with "power". Those who happen to know the WMI class Win32_Process may have recognized that all the demonstrated things can be done easily by this class. But PowerShell can do more: WMI doesn't expose properties such as company or product version, but PowerShell does. In the following example, Get-Process gets piped through the Select-Object Cmdlet, filtering out any information except the process name, product version, and the company:
Get-Process powershell | Select-Object name,productversion,company
Now you ask yourself how you are supposed to know which properties are available through get-process, don't you? You can find it out by yourself. The following line pipes get-process through get-member and displays all available members:
Get-Process | Get-Member
Try it out by yourself - You'll get a very long list of Members, and you are free to use all of them.
Of course you will sooner or later encounter the situation that you need to stop a running process - Use the stop-process Cmdlet to do it. It accepts either a process id or process name as parameter:
Stop-Process 23498
Stop-Process -processname notepad
Use .Net classes within your PowerShell Script
The following function starts a process using the .Net System.Diagnostics namespace. Of course the same can be achieved by simply using the Start-Process Cmdlet, but it gives you a good start on the syntactically correct way to use .Net classes in your PowerShell Script.
function StartProcess([string]$filePath, [array]$arguments, [bool] $waitForExit)
{
$pinfo = New-Object System.Diagnostics.ProcessStartInfo #Make a new Process start info object
$pinfo.FileName = $filePath #set the file name to the filePath argument
$pinfo.RedirectStandardError = $true #standard error and stdout shall be redirected
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = $arguments #set the arguments to the arguments specified $arguments
$p = New-Object System.Diagnostics.Process #create a process
$p.StartInfo = $pinfo # assign start info to the process
$p.Start() | Out-Null # start the process
IF($waitForExit){ #wait until the process has exited (if specified)
$p.WaitForExit()
}
}
Utilities
This chapter gives some examples of PowerShell functions I wrote myself. All of these functions provide a functionality which isn't given by existing Cmdlets, but still of use in many cases.
Create a directory if it doesn't exist
Just creating a directory throws an error if the directory already exists. This little helper function avoids this problem by only creating the directory if it doesn't exists:
function CreateDirectoryIfNotExisting([string]$dirPath){
IF(!(Test-Path -Path $dirPath)){#check if the directory exists
New-Item -ItemType directory -Path $dirPath #create it if it doesn't exist
}
}
Abort script execution if a file/directory is missing
This function aborts the execution of the script if the specified file is missing on the file system.
function AbortIfFileMissing ([string]$filePath, [string]$name)
{
IF(!(Test-Path $filePath)){#Not being able to find file throws
Throw ("ERROR: The File $name was not found! Expected path: $filePath")
}
ELSE{
Write-Host ("File " + $name + " found. It's located at " + $filePath)
}
}
The function which has the same functionality regarding to a directory can be implemented following the same scheme:
function AbortIfDirectoryMissing ([string]$dirPath, [string]$name)
{
IF(!(Test-Path $dirPath)){#Not being able to find directory throws
Throw ("ERROR: The directory $name was not found! Expected path: $dirPath")
}
ELSE{
Write-Host ($name + " found. It's located at " + $dirPath)
}
}
Further reading
This chapter gives you a collection of Links which you can use to read further, more detailed information about specific PowerShell topics.