How to get started writing a PowerShell script | From idea to action
When you’re given a task or you have a task you want to automate, what approach do you take? What kind of steps do you do? Let’s say you want to copy files from a directory to another.
The first thing I like to do is to see what kind of cmdlets that is available in regards of the task you want to solve. This can be done by running the following command:
With this command you can filter on parameters like name, noun and verb to find the most suitable cmdlet to use. Since we are going to create a script that copies files, we can get all commands containing copy with the examples below. Note, that I might have different modules and cmdlets installed, therefore some cmdlet may be different. From the result below, we will use the cmdlet
When we have found the proper cmdlet, we need to know how it can help us, by asking for help. This can be done by using the cmdlet
Get-Help. This gives you a manual on how the cmdlet works. and there are many different ways you can ask for help, that is often useful when learning about a new cmdlet. See some examples below.
Now that we know a thing or two on how to get help, we can start by testing out the cmdlet in the command line. Lets say you want to take copy of your Documents folder to a Backup folder, we can do this by running the following command.
This command does the trick, but typing this command for each item in a folder manually isn’t very efficient. Now, let’s see how we can do this for each item within a folder now that we have the core command in place.
Looping through folders
To find how we can loop through each item in a folder we can use
foreach lets us repeat a section of code, in this case repeating the
Copy-Itemcmdlet for each item in a specified directory, but first we need to now how to list out all the items in a folder. To find out, we can use the
Get-Command again to look for something that lists items in a current directory.
Now that we now how to list items in a directory and we know how to repeat a task for each item in a directory, we can now combine these two cmdlets with the following.
The first example code says for each object in the parentheses, perform the action that’s defined within the curly braces. The
Get-ChildItem in the
foreachstatement grabs a list of items in the specified path and stores them temporarily in the
$itemvariable. Inside the loop the variable
$itemis used to refer to the single object returned by this particular iteration of the loop. For each iteration the
Copy-Item command is called and the item is moved to the specified destination.
The second example pipes the result from the
Get-ChildItem cmdlet to the
foreachcommand and for each item copy the result to the specified destination. The
$_ variable can be seen as the
$itemvariable in the first example, it refers to the single object returned by the particular iteration of the loop. This is one way we can repeat tasks for multiple items.
Furthermore, that we can copy all items in a folder, we can further enhance the script by adding variables. This makes it easier to edit what the parameters in the script, by separating the functionality and values, it’s also a step towards avoiding hard coded values. If you save and run the script below you will be able to copy items specified in the
$Pathvariable to the path specified in the
$Destination variable. By creating variables you can edit the value without editing the action of the command. Save the file as
Copy-Items.ps1 and then run it from the command line and the script will execute the script (if you have the same file and folders) otherwise it will display an error message that the current path doesn't exists. Execute the script by running for instance
Parameterizing the script
To enhance the script even more we can add parameters to the script, this allows us to specify the value of the variables, which let’s us specify the directory we want to copy and the destination we want to copy, each time we run the script. To execute the script below with parameters, you can do as follow:
C:\Scripts>Copy-Item -Path C:\Documents -Destination C:\Backup. It allows us to specify the values of the variables more interactively than in the previous step, and is starting to become a more useful tool.
To further improve the script we can explicit define the data type of the parameters. This helps validating that the input parameter has the correct data format.
Creating a function
Further more, we can create a function out of the script. A PowerShell function is a list of statements that has a name assigned to it, in this case we call it , since we are copying all items in a specified folder. To call a function you need to load the script into memory by using dot source like this
. C:\Scripts>Copy-Items.ps1, then you can run the function just like a PowerShell cmdlet,
Copy-Items -Path C:\Documents -Destination C:\Backup.
Remember when you’re working with a function you must load it into memory each time you make an adjustment to it, otherwise you can be quite confused when you run the script and nothing different is happening. It can be useful to open a new PowerShell instance with or using the up arrow on the key board to reuse the dot source command, this is quite effective when you get use to it.
When creating function and PowerShell tools, use the same naming convention as the PowerShell cmdlets. This makes it more intuitive and easy to use by keeping it consistent. You don’t need to invent the wheel again. For instance in the script we have created I’ve used the same variable names as the parameters to keep it consistent and intuitive, and easier for other to get started when there is one way to name variables and parameter names.
More, when creating a function use the Verb-Noun naming standard. To get a list of all available verbs in PowerShell, you can use the cmdlet
Get-Verb. Use a verb that matches to action of the script and make sure to use descriptive names that explains the functionality of the script. Also use the PowerShell case standard, Pascal case.
In short the reason you want to follow the PowerShell naming convention is that you want to build your tools and functions to be exactly like a PowerShell command.
Creating a cmdlet
[CmdletBindng()] to the script. When PowerShell see this attribute, it treats the command like a cmdlet. A cmdlet has a lot of neat features, one of them is the cmdlet
Write-Verbose, this allows you to verify what the script is doing while running, by outputting a descriptive text you can activate when the function runs, by adding the
-Verboseparameter, like so
Copy-Items -Path C:\Documents -Destination -Verbose. The
[CmdletBindng()] also a has other features like
ErrorAction and more. In this post we focus on
When you run the function, this will output
A final touch
Now we have a full worthy script that let’s us copy files within a folder to another folder, the last thing we need to do is creating documentation of the script.
If you now run
Get-Help Copy-Items, you can get the help information about the cmdlet, this is useful if you have created the script once, and then need to run in a later state, also if others is using the tool.
To wrap up
Now we have create a simple script using simple steps to create a fully working script. I hope you find the steps useful and understandable. I’ve also added a list below with some other tips that came to mind when writing this post. Hope you enjoyed and learned something from it.
- Don’t start creating a script, the first step is to test and figure out the core command in the console. Then when you’re troubleshooting you only have one problem to relate to, then take baby steps until you have a fully working tool, like we did in this post.
- Use double quotations when using cmdlets like
Write-Output, then you can use variables without have to concatenate.
- If you us PowerShell ISE you can put your cursor on a cmdlet, and hit F1 and then a new window with the help manual for that cmdlet opens up.
- Don’t use
Write-Hostif you plan to make modifications to the object you write to the console, this cmdlet will only output plain text, while
Write-Outputkeeps the object in place, and you can make modification to the object. The is
Write-Hostuseful when writing status updates when scripts are run by using it's parameter
-Foregroundcolorwhere you add colors, for instance; red for errors, green for success, yellow for warning.
Originally published at https://www.fredrikengseth.com.