Search file content by keyword using Everything + PowerShell + GUI →
Even with Windows 10 MS still didn’t manage to include a proper in-built file search functionality. If it is about searching for files I definitely prefer the excellent Everything search engine (see also my post on a PowerShell wrapper around Everything commandline) .But quite frequently I also need to search for keywords/pattern within files. PowerShell’s Get-ChildItem and Select-String can certainly do this together: [code language=”powershell”] #search through all .ps(m)1 files for instances of the word ‘mySearchString’ $path = ‘c:\scripts\powershell’ Get-ChildItem $path -Include (“.ps1”,”.psm1”)) -Recurse | Select-String ‘mySearchString’ | select Path, Line, LineNumber [/code] While this does the job it doesn’t follow my preferred workflow and is also not very quick when running it against a large set of files. I would prefer to have the ability to search and drill down a list of files within a Graphical User Interface just like Everything and then search through the filtered list of files using keyword(s)/pattern(s) and get back the search results within a reasonable time-frame. Say hello to “File Searcher” (I didn’t spend any time thinking about a catchy name): The three text boxes at the top of the UI can be used to:
MathJax Example
MathJax is a simple way of including Tex/LaTex/MathML based mathematics in HTML webpages. To get up and running you need to include the MathJax script in the header of your github pages page, and then write some maths. For LaTex, there are two delimiters you need to know about, one for block or displayed mathematics \[ ... \]
, and the other for inline mathematics \( ... \)
.
Finding the index of an object within an array by property value using PowerShell →
![1500333523685c69638c_m](https://powershellone.files.wordpress.com/2015/08/1500333523_685c69638c_m.jpg)
Today I was looking for an option to find the index of an object within an array of objects. Using an array of one dimensional objects like integers this is as simple as using the static IndexOf method of the Array class in the System namespace:
[code language=”powershell”]
$array=10..1
$index = $array.IndexOf(3)
$array[$index]
[/code]
But in my case I wanted to get the index of an item within an array of multidimensional or rich objects. As an example let’s say after running Get-Process we would like to find the index of the process whose Name property equals “powershell” (the return type here is an array of System.Diagnostics.Process objects).
My first approach was to use the Select-String cmdlet since I knew it returns a LineNumber property. After some trial and error I came up with the following:
[code language=”powershell”]
$processes = Get-Process
$index = (($processes | Out-String).Split(“n") |
Select-String "powershell").LineNumber
#index needs to be decremented by 4 since the data starts at line 3 and LineNumber is 1 based
$processes[$index-4]
[/code]
While this returns the desired result it's not a very robust solution. If there is, for example, powershell and powershell_ise running at the same time this would return two line numbers instead of one. Furthermore, the approach does not permit to look for items by property values (unless you throw in some crazy regex).
Ok, let's give it another try. The problem with the $processes array is that it doesn't have an index property, but fortunately, with PowerShell it's not a problem at all to add one:
[code language="powershell"]
$processes = Get-Process | foreach {$i=0} {$_ | Add-Member Index ($i++) -PassThru}
$index = ($processes | where {$_.Name -eq "powershell"}).Index
$processes[$index]
[/code]
This looks already better. Adding an Index property to the array makes it easy to replicate the IndexOf method's functionality with an array of rich objects. It still involves quite some steps, though. Looking for yet another approach, I came across the [FindIndex method](https://msdn.microsoft.com/en-us/library/x1xzf2ca(v=vs.110).aspx) that is part of the System.Collections.Generic namespace:
[code language="powershell"]
$processes = [Collections.Generic.List[Object]](Get-Process)
$index = $processes.FindIndex( {$args[0].Name -eq "powershell"} )
$processes[$index]
[/code]
With that approach, we first need to cast the array to generic list. Generics are a concept of strongly typed languages like C# which make it possible to write a method that can be used against multiple types of objects (hence generic). For PowerShell, this doesn't matter so much since its type system is rather dynamic and mainly implicit therefore we just use a generic list of objects (kind of a generic generic list) here. The FindIndex method expects a typed predicate as its only argument which in PowerShell conveniently translates to a ScriptBlock. The predicate is exactly the same as what is used as the FilterScript parameter for the Where-Object cmdlet. The only difference is that we need to use the built-in [$args variable](https://technet.microsoft.com/en-us/library/hh847768.aspx) in order to access the current ("Pipeline") element instead of "$_".
How do those approaches compare in terms of execution speed?:
[code language="powershell"]
@'
(gps | foreach {$i=0} {$_ | Add-Member Index ($i++) -PassThru} | where Name -eq "powershell").Index
((gps | out-string).split("
n”) | sls “powershell”).LineNumber
(Collections.Generic.List[Object]).FindIndex({$args[0].Name -eq “powershell”})
‘@ -split “`n” | foreach{
(Measure-Command ([ScriptBlock]::Create($))).TotalSeconds
}
[/code]
On my machine I got 0.21, 1.67, 0.02 respectively. Looks like the last approach also outperformed the others by at least an order of magnitude.
PowerShell tricks - Build an array of strings without quotation marks →
This is one of the tricks I keep forgetting about and therefore document it here for myself but also in case someone else might find it useful.
In order to create an array of strings one usually does something like this:
[code language=”powershell” light=”true”]
$stringArray = “first”, “second”, “third”, “fourth”
[/code]
It involves quite some redundant characters in order to do a simple thing. This can be made easier using a simple function that is part of the excellent PowerShell Communicty Extensions. The QL (QL is short for Quote-List an idea borrowed from Perl) function has the following definition:
[code language=”powershell”]
function ql {$args}
ql first second third fourth
[/code]
Note that extraneous commas and quotation marks can be avoided using this approach. There is actually even a built-in cmdlet that can be used for the same purpose. Write-Output alias echo or write:
[code language=”powershell” light=”true”]
echo first second third fourth
[/code]
If an element of the string array we’d like to create contains a space the element needs to be surrounded in quotes:
[code language=”powershell” light=”true”]
echo first second third fourth “with space”
[/code]
As a bonus tip we can use a similar idea as for the ql function in order to create strings without having to limit them by quotation marks:
[code language=”powershell”]
function qs {“$args”}
qs this is a long string without any quotes
#only gotcha is when using quotes (single or double) within the argument
#qs this does not’ work
qs quotes require escaping using a 'backtick
’ otherwise it will not work
[/code]
Sort data using a custom list in PowerShell →
Using the Excel intersection operator →
One of the lesser-known features of Excel is the intersection operator which can be used to simplify look-up operations. An intersection is the overlap of two or more cell ranges within excel. For instance: In the screenshot below the ranges C1:C5 and B3:D3 (Cell ranges in Excel are written by using the range operator “:”) overlap in the cell C3. The intersection operator “ “ (a space) can be used to find the intersection of ranges. To find the intersection of the two ranges one can just use the following formula “=C1:C5 B3:D3”: Combining the intersection operator with named ranges yields to pretty intuitive look-ups in Excel. Let’s take up another example using monthly revenue data by region: Highlighting the table and pressing CTRL+SHIFT+F3 will bring up the “Create Names from Selection” dialog. We can go with the defaults (Top row, Left column) in order to create named ranges for each column and row within the table based on their labels: Now, in order to retrieve the March Results for the East region we can simply use “=March East”: Getting the Sum of the revenues from January-April for the West region is equally simple “=Sum(January:April West)”: Even non-consecutive ranges can be easily referred to. Pulling up the Sum of revenues for the month of January, March, and May for the South region is as easy as typing “=Sum((January,March,May) South)”: