Pedro Osternack Corrêa
Posted on January 4, 2022
This is the first part of my "Being lazy with PowerShell" series were I'm documenting my exploration of the language by solving some simple problems. If want more context on what we're doing here please check the introduction post here.
TL; DR;
Here's the final snippet for this post.
$reposFolder = "C:\repos\"
$repos = @{
client = "client-portal";
dash = "service-dashboard";
users = "users-api-v4";
devops = "devops-toolkit";
main = "backend-monster";
data = "data-bridge";
}
$repos.Keys | ForEach-Object { New-Variable -Name $_ -Value ($reposFolder + $repos[$_])}
This will generate one variable on the local scope of your PowerShell session for each entry on the $repos
HashMap, and you can use them to easily navigate to the repo folders like this: cd $client
.
If you want a more in-depth explanation of what's going on just keep scrolling :D.
Initial Setup
My first attempt is kind of simple, I'll create a new variable for each repo that I have, but I want to do that programmatically.
The first step was to create a HashMap with all the repos. On one hand I could list my repos
folder and go from there, but the HashMap approach gives me the option of defining a key for each folder and use that as the variable name. Also I'm getting started so want to keep the logic very as light as possible.
So, this is what my repos folder looks like:
PS C:\repos> ls
Directory: C:\repos
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2021-12-14 8:52 PM backend-monster
d----- 2021-12-14 8:52 PM client-portal
d----- 2021-12-14 8:52 PM data-bridge
d----- 2021-12-14 8:52 PM devops-toolkit
d----- 2021-12-14 8:52 PM service-dashboard
d----- 2021-12-14 8:52 PM users-api-v4
Based on that I've created the following HashMap:
$repos = @{
client = "client-portal";
dash = "service-dashboard";
users = "users-api-v4";
devops = "devops-toolkit";
main = "backend-monster";
data = "data-bridge";
}
Here I've mapped each one of my repos to a key that identifies them and that I'll use to identify my variables, such that the client-portal
should be the value of the variable $client
portal, and so on.
Building the script
Now that we have a map we need to iterate over my $repos
map, for that end we can use either the HashMap ForEach
method or the ForEach-Object cmdlet, I'll use the latter here, but they'll give us the same results. (there are more ways of solving this problem and I'll list the ones that I know at the end just as a curiosity)
Now, you cannot iterate over a HashMap in PowerShell the same way you can over an Array. By that I mean that if we just use the following command we will only see "Hello" printed once on our terminal.
$repos | ForEach-Object { "Hello" }
To be able to iterate over each item we can use either $repos.Keys
to get each key of the map or $repos.Values
to get each value of the map. So if we update the snippet above to use the Keys
property, we should see Hello
being printed once for each item on the map (6 times in this case).
$repos.Keys | ForEach-Object { "Hello" }
Ok, let's step back for a bit. What's happening on the snippet above is: we're evaluation $repos.Keys
which will return each key on our map to the console, and passing that result to the ForEach-Object
cmdlet using the pipe operaton |
. That ForEach-Object
cmdlet will print Hello
for each item returned by the previous command ($repos.Keys
in this case).
What is the difference between both snippets then? On the first one, evaluating $repo
will return only one result, which will be the full map, so the ForEach-Object
will only have 1 entry to work with. On the other hand, $repos.Keys
will not return the list of keys, but each key
inside of that list, which means that the ForEach-Object
will receive 6 entries. Interesting, right?
Moving on. We can iterate over the keys of our map, and now we want to use them. to do so we can use the $_
variable. That is a special variable that powershell gives us so we can get current item being iterated over inside of the foreach loop. So, if we update our snippet again we will see all keys being printed on our console.
PS C:\repos> $repos.Keys | ForEach-Object { $_ }
dash
data
devops
client
users
main
Ok, good, from here we need to access the value for those keys. To do so we can use them as indexes on the map like this: $repo[key]
. Let's update the snippet once again.
PS C:\repos> $repos.Keys | ForEach-Object { $_ + " -> " + $repos[$_] }
dash -> service-dashboard
data -> data-bridge
devops -> devops-toolkit
client -> client-portal
users -> users-api-v4
main -> backend-monster
Now all we need to do if define our new variables. The easiest way I could find to do that is by using the New-Variable cmdlet. We can than pass our key as the -Name
argument and the path to the repo as the -Value
argument to that cmdlet and we should be good to go. The path for the repos is a combination of the path to my repos folder (c:\repos
) and the folder name in the map. The script should look something like this:
$repos.Keys | ForEach-Object { New-Variable -Name $_ -Value ("C:\repos\" + $repos[$_])}
After running the above script now we should have available on our terminal one variable for each entry on our map. We can call them by prepending $
to the key. They should look something like this
$dash -> C:\repos\service-dashboard
$data -> C:\repos\data-bridge
$devops -> C:\repos\devops-toolkit
$client -> C:\repos\client-portal
$users -> C:\repos\users-api-v4
$main -> C:\repos\backend-monster
And we can use them in combination with cd
(or Set-Location if you want to get fancy) to navigate to our repos, ex.: cd $dash
should send us to the C:\repos\service-dashboard
directory and so on and so forth.
About the solution
This certainly works. I can have aliases for my folders and need to type less to get to my repos, but it's not there yet.
One issue is adding a new folder requires to create a new entry on the map on my posh profile. Admittedly this is not a huge issue, mainly if you consider the likeliness of adding new projects to the specific solution or how often that would happen.
Also we need to be very conscious of our variable names to not create unwanted conflicts, which may be a bigger problem if you rely on posh for your day-to-day work.
And there's also the small issue of needing to type cd $
, the main problem being the $
I really want to avoid that. (Please note that this is not a problem at all, I just want an excuse to try some new stuff, so bear with me.)
So for my next attempt I'll probably try to tackle some of those points.
Well this is it for now, hope that you've liked this first post and maybe found it somewhat useful. See you on the next one.
Posted on January 4, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.