Subscribe via Email

Subscribe via RSS


Creative Commons Attribution 4.0 International License
© Rakhesh Sasidharan

Search Firefox bookmarks using PowerShell

I was on Firefox today and wanted to search for a bookmark. I found the bookmark easily, but unlike Chrome Firefox has no way of showing which folder the bookmark is present in. So I created a PowerShell script to do just that. Mainly because I wanted some excuse to code in PowerShell and also because it felt like an interesting problem.

PowerShell can’t directly control Firefox as it doesn’t have a COM interface (unlike IE). So you’ll have to manually export the bookmarks. Good for us the export is into a JSON file, and PowerShell can read JSON files natively (since version 3.0 I think). The ConvertFrom-JSON cmdlet is your friend here. So export bookmarks and read them into a variable:

This gives me a tree structure of bookmarks.

Notice the children property. It is an array of further objects – links to the first-level folders, basically. Each of these in turn have links to the second-level folders and so on.

The type property is a good way of identifying if a node is a folder or a bookmark. If it’s text/x-moz-place-container then it’s a folder. If it’s text/x-moz-place then it’s a bookmark. (Alternatively one could also test whether the children property is $null).

So how do we go through this tree and search each node? Initially I was going to iteratively do it by going to each node. Then I remembered recursion (see! no exercise like this goes wasted! I had forgotten about recursion). So that’s easy then.

  • Make a function. Pass it the bookmarks object.
  • Said function looks at the object passed to it.
    • If it’s a bookmark it searches the title and lets us know if it’s a match.
    • If it’s a folder, the function calls itself with the next level folder as input.

Here’s the function:

I decided to search folder names too. And just to distinguish between folder names and bookmark names, I use different colors.

Call the function thus (after exporting & reading the bookmarks into a variable):

Here’s a screenshot of the output:


Scope in PowerShell

PowerShell variables and functions have scope. The “scope” is what defines the visibility of that variable or function.

For instance, consider the following script:

If you were to run this script, here’s the output:

As you can see, the variable x was set as 2 initially but when the function blah set it to 5 the change didn’t really affect it. This is because of scopes. What happens is that the script variable x belongs to a different scope from the function variable x and although both have the same name they are in fact two different beings. In a way it’s like the variables are in two different boxes – each script/ function has a box full of variables, and whatever change they make to the variables in their box doesn’t affect the variables in other boxes. This is the case even if a function is within a script or another function – the child-function has a box of variables independent of its parent.

Now, the concept of scopes only matter when you are making changes to a variable. If you were just reading the value of a variable then scope doesn’t matter much. Consider the following script:

Here even though the function blah has a box of its own variables, when we refer to variable x within it since the variable is not present in its box it looks up to the box of its parent and reads the value from there. Hence the output of the script is:

But suppose we had made a change to variable x within the function (as in the first case), then a new variable x is created within the scope of that function and whatever change we make is limited to that variable.

There are four types of scopes:

  1. Local scope: the box you have, the current scope basically of the script or function you are in.
  2. Global scope: the big box that’s out there, the scope containing all variables that are in your particular PowerShell session (be it a PowerShell window or ISE)
  3. Script scope: another big box, but not as big as the global scope and not as limited as the local scope, this is the scope containing all variables that are in your particular PowerShell script session. The script scope is like a global scope for scripts.
  4. Private scope: a secret box you have, containing variables you don’t want your children to see. Remember I said earlier that if a variable is not present in a function it looks to the parent scope and reads it from there? If you have any variables you don’t want such children functions to see, define them in a private scope.

Consider the following script:

This is just to illustrate the first three scopes mentioned above. Here’s the output from the script:

The variable x was set as 2 initially. Function blah changed it to 5, but that only took effect in the local scope of the function and so x was still 2. Next, function blah2 changed x to 5 in the global scope (by addressing the variable as $global:x), but that too didn’t change the value of x as the change was made in the global scope and not the script scope. Finally, function blah3 changed x to 5 in the script scope (by addressing it as $script:x) and that effected the change.

From this example one can also see the need for a script scope and a global scope. Function blah3 changed variable x globally within the script, but any variable x existing outside the script and in the PowerShell session was unaffected. Similarly function blah2 changed variable x within the PowerShell session of the script, but the variable x within the script itself was unaffected (of course, if the script didn’t have a variable x then any references to x will pick up the variable from the global scope). If we didn’t have separate scopes for scripts and the PowerShell session, all scripts would mess about with the global scope variables.

Note though: The global scope and script scope are separate only if the script is run and not dot-sourced. If a script is dot-sourced, the script scope becomes the global scope.

And lastly, private scopes. Consider this script:

And here’s the output:

Since y was defined with a private scope in the script, function blah can’t read its value.

Scopes can also be referred to by a number. 0 is the local scope, 1 is the parent scope, 2 is the grandparent scope, and so on. This is useful with the Get-Variable cmdlet, for instance. Consider the following script:

Its output is thus:

As you can see, there are only two scopes – 0 is the local scope (the script scope in this case), 1 is the global scope. If I had defined a function within the script, then scope 0 would be the local scope, 1 would be the script scope, and 2 would be the global scope.

Accessing scopes by number is also useful with cmdlets such as Set-Variable. For instance, the following sets a variable in the parent scope of the calling script:

That’s all for now. It’s worth reiterating that within a script you have a global scope and a script scope, and the two are separate. Setting a variable in the global scope from a script does not affect the variable in the script scope.

PowerShell functions can’t have a parameter called input

This bit me once in the past, and again today. What a waste of time!

PowerShell functions can’t have a parameter called input. No error is thrown when you define the parameter thus, it just doesn’t work that’s all.

What about if I try constraining the parameter type?

Still the same, just that I get a weird error too. Looks like the default parameter input is of type ArrayList.

Update: Later I learnt that all PowerShell functions have a default variable called $input (similar to the default variable $args). When the function accepts input from a pipeline this variable is what holds the input.

Using closure to capture the variable value in a script-block

You can’t use New-Item to create new functions or aliases. It only works for files and directories.

But you can use Set-Item to create new functions and aliases.

How would I go about making a bunch of functions via a loop? The following code creates functions named Hello-<num> which output <num> when run.

Does this work?

And there lies the problem. Instead of each definition containing the number as it’s supposed to be, they all contain the variable $i. And since $i is 10 when the foreach loop terminated, all functions return the number 10.

I can test this by setting $i to a different number:

What I need is for $i in the Set-Item script-block to not be left as a variable, but to be “captured” (for lack of a better word) and set to whatever the value of the variable is at the time the script-block is created.

If you examine the members of a script-block you’ll notice a method called GetNewClosure(). That’s what I need to use here. This method “closes off” (like “closing a deal” or “let’s close somebody”, similar to “capturing somebody”) all variables in the script-block when it’s created.

Good to know!

Closures work with function parameters too. No side-effects as far as I know.