Monthly Archives: August 2015

Script Sharing – Get Synonyms for Approved and Unapproved Verbs

Download link at bottom of post. Note: This post contains information that is necessary to know to use this function. Please read it if you think you’ll try using this function.

Update: The previous version of the function (1.0) required the user to register and obtain an API key, and place it inside the function’s code. I’ve only had some 40 downloads, so I’ve opted to include my API key to see if this function can get more usage. This really can be a great tool, and so it seems the best idea for now. If anyone ever hits an error using the API key, please let me know: <my1stname>@<thisdomain>.com. (6/10/2016)

I consider myself a best practice kind of guy; especially when it comes to Windows PowerShell. There’s been a time or two where I’m quite sure that I, politely, called someone out for using an unapproved verb. If you’re familiar with PowerShell, then you know that cmdlet and function names should use the verb-noun naming convention. Now, no one cares about the nouns you choose, but verbs need to be approved.

If you haven’t before, try running the Get-Verb cmdlet. This cmdlet, when used without any parameters, will return all the approved verbs. Even for me, there’s been a time or two when the verb I wanted to use wasn’t approved. In that case, I recommend still finding and using an approved verb, but also creating an alias that you can use to call your properly named, cmdlet or function. Here’s a modified example from one of my previous posts:

Set-Alias -Name Launch-InternetExplorer -Value Open-InternetExplorer
 
Function Open-InternetExplorer {
    # Do Stuff.
}

In this example, that was originally posted here: http://tommymaynard.com/quick-learn-create-a-function-to-open-internet-explorer-like-in-run-2015, I can use Launch as my verb, since I’ve made it part of an alias. The function name with the approved verb is Open-InternetExplorer and my alias, that will run this same function, is Launch-InternetExplorer.

So, where am I going with this: I’ve always wanted a function that would allow me to pull back synonyms for a verb, and today, I have just that. I considered walking though what I did to write this, but instead, because it ended up being somewhat lengthy, I posted it on TechNet for download.

Before I provide a download link, I should mentioned that you’re going to need to do a couple things to make this function work for you.

  1. Go to http://thesaurus.altervista.org/mykey and register for an API key.
  2. Download my function from the link at the bottom of the page.
  3. Open the function in the ISE, or your editor of preference, and replace [string]$Key with [string]$Key ='<Your API Key>’, replacing <Your API Key> with key you received from step 1.

Now when you use the function, it’ll use your API key. In addition, we won’t have to make the -Key parameter mandatory, forcing it to prompt us for the key, even when the $Key variable is being assigned a value inside the function. Thanks!

get-synonyms-for-approved-and-unapproved-verbs01

Update: The newest version is now available for download on the PowerShell Gallery.

Download the Get-TMVerbSynonym advanced function here: https://gallery.technet.microsoft.com/Get-Synonyms-for-Approved-f6625752

Twitter Reply – Finding Parameters that Include a Default Value

Adam Bertram, an active PowerShell MVP, wrote on Twitter about the need to determine which parameters have default values. I can’t resist a challenge, and so I very quickly wrote out the function below. No guarantees, but maybe it’ll help.

Update: It turns out that the function that Adam was working with, didn’t include help. Shame. Even so, this small script may assist someone to pull back the parameters that have default values.

Get-Help Get-Service |
    Select-Object -ExpandProperty parameters |
    Select-Object -ExpandProperty parameter | 

    Foreach {
        If ($_.DefaultValue -ne '') {
            $Object = [pscustomobject]@{
                Name = $_.Name
                Default =$_.DefaultValue
            }
        Write-Output -InputObject $Object
        }
    }

Save External Dynamic IP to Dropbox

There are times when I’m away from the house, where I need to be able to reach my home computer via Remote Desktop. Because of this occasional need, I have my home router set up to allow this external connection. To do this required a static (internal) IP assignment for my home computer (I actually use a DHCP reservation), my router listening on port 3389 on the outside IP, and port forwarding that routes this external traffic to the home computer’s internal IP address. I used to connect by name, but the application I was using to sync my IP with my hostname, doesn’t seem to be working consistently. Therefore, I’ve been using my fallback option a lot lately: PowerShell and Dropbox.

Here’s what happens: I have a scheduled task on my home computer that runs a PowerShell script at 12 a.m., 6 a.m., 12 p.m, and 6 p.m. each day. The purpose of the script is to get my current, outside IP and write it, as well as the date and time, to a text file in Dropbox. That file is then snyced to my other computer and phone. It’s simple.

In line one, below, we create a variable, $UseableDate, to hold the string I use for the date and time. For today’s date, it might look something like this: D2015-08-19_T09-02-43-PM. This has long been my preferred way to store the date and time, especially when used in file names, as it will keep everything in a sort able order by year, month, and then day, and doesn’t include any invalid characters when used in a file path.

$UseableDate = Get-Date -Format 'Dyyyy-MM-dd_Thh-mm-ss-tt'

Next we need to collect the outside IP address. This is an important distinction — I don’t want my internal, NAT’d IP address. Line two, below, which checks in with dyndns.com, was borrowed from Aman Dhally. I’ve included a couple other options that can be used to populate the same $IPAddress variable (note: ifconfig.me has always seemed to be slower than the rest). Notice that using something other than dyndns will not require using any Regex, just some trimming to remove some white space surrounding the IP address.

$IPAddress = (Invoke-WebRequest -Uri ‘http://wtfismyip.com/text’).Content.Trim()
$IPAddress = (Invoke-WebRequest -Uri ‘http://ifconfig.me/ip’).Content.Trim()

$UseableDate = Get-Date -Format 'Dyyyy-MM-dd_Thh-mm-ss-tt'
$IPAddress = (Invoke-WebRequest -Uri 'http://checkip.dyndns.com').Content -replace "[^\d\.]"

The third line in the script, joins the date and time with the IP address and writes (appends) it to the file inside my Dropbox folder. Again, this is running from my home computer. Once in Dropbox at home, my work computer and phone will have the newest version of the file. In fact, it’s become a pretty good reminder that it is lunch time at work, as Dropbox pops up a Notification Area balloon that my file has been updated at 12 p.m.

$UseableDate = Get-Date -Format 'Dyyyy-MM-dd_Thh-mm-ss-tt'
$IPAddress = (Invoke-WebRequest -Uri 'http://checkip.dyndns.com').Content -replace "[^\d\.]"
"$UseableDate -- $IPaddress" | Out-File -FilePath 'C:\Users\tommymaynard\Dropbox\IP\homecomputer-IP.txt' -Append

To be as complete as possible, and save as many seconds as I can per day, I have a little function in my profile on my work computer to grab the IP address from the file. First, here’s an example of my homecomputer-IP.txt file (with hashtags taking the place of the digits):

...
D2015-08-18_T06-00-03-PM -- ##.###.##.###
D2015-08-19_T12-00-06-AM -- ##.###.##.###
D2015-08-19_T06-00-07-AM -- ##.###.##.###
D2015-08-19_T12-00-06-PM -- ##.###.##.###
D2015-08-19_T06-00-03-PM -- ##.###.##.###

The function below will extract the last IP address added to the homecomputer-IP.txt file. With that, I can add it to the Remote Desktop command line executable and get connected to the home computer from anywhere.

Function Get-HomeIP {
    $IPFile = 'C:\Users\tommymaynard\Dropbox\IP\homecomputer-IP.txt'
    (Get-Content -Path $IPFile | Select-Object -Last 1).Split(' -- ')[-1]
}
PS> Get-HomeIP
##.###.##.###
PS> mstsc.exe /v (Get-HomeIP)

That’s it — I hope this might be helpful to someone, someday. It’s saved me a time, or two now.

Update [02/09/2017]: I recently made a couple changes to the above function. The problem was that sometimes the IP wasn’t written to the file, for whatever reason. In this instance, my function ends up returning nothing. Therefore, I now sanitize the file first, so that any rows that don’t contain an IP address are excluded. Take a look.

Function Get-HomeIP {
    $IPFile = 'C:\Users\$env:USERNAME\Dropbox\IP\homecomputer-IP.txt'
    $SantizedIPs = Get-Content -Path $IPFile | Where-Object -FilterScript {$_.Length -gt 34}
    ($SantizedIPs | Select-Object -Last 1).Split(' -- ')[-1]
}

Copy Outlook Signature to Clipboard

As far as I am aware, the in-house built front end for our help desk ticketing system, doesn’t have a way to include a signature. This means that as I update and close tickets in the office, I often find myself opening a new, blank email, copying my signature, and pasting it in the notes field on the ticket. I know, I know — I’m embarrassed.

No more, am I going to consider this acceptable, especially for someone that uses PowerShell for as many things as I do: it’s. always. open. Today was the day I fixed this forever, and it took a whole two minutes.

I needed to first determine where Outlook (2013 on Windows 8.1) looks for my signature. I traced it down to C:\Users\tommymaynard\AppData\Roaming\Microsoft\Signatures. In that path there are three files named Standard — the same name used for my Signature in Outlook, when I open the Signatures and Stationary dialog. There is a .htm version, a .rtf version, and a .txt version of the signature. Simple decision: I decided I would make use of the text file.

Since I was going to use this in my profile, I didn’t include anything inside the function, but the simple command I wanted to run. Based on the function below, all I need to do is enter Get-Signature, or its alias, and my function will copy the contents of Standard.txt to my clipboard. From there, it’s a quick paste into the help desk ticketing system, and done.

Set-Alias -Name sig -Value Get-Signature
Function Get-Signature {
    $SigPath = 'C:\Users\tommymaynard\AppData\Roaming\Microsoft\Signatures\Standard.txt'
    Get-Content -Path $SigPath | Select-Object -First 4 | clip
}

If you’ve taken a look at the function, you’ll see that I only choose the first 4 lines of the signature file. This was because there was a blank line beneath the last line in my signature, that I wasn’t interested in copying (or manually removing from the file itself).

Parsing nslookup: Only Return the Resolved IP

It was late last Friday evening when a vendor and I worked though some maintenance. As a part of the work (which actually lasted well into the weekend), we needed to remove two DNS A records and replace them with CNAME records. I figured that before the change, I would return the current resolution results, so I would be able to ensure the DNS change took place, after the night’s weekend’s work.

You’re probably familiar with the standard output of nslookup.

PS> nslookup subdomain.mydomain.com
Server:  mydomain.com
Address:  10.10.10.1

Name:    subdomain.mydomain.com
Address:  10.20.30.40

These results indicate the name, subdomain.mydomain.com, resolves to an IP address of 10.20.30.40 when using the mydomain.com nameserver, at 10.10.10.1. I wanted to clean up this output, and since I had time to kill while fighting off sleep, I figured — why not? I started by piping the results of nslookup to the Select-String cmdlet looking for the string, ‘Address.’ As you can see in the example below, it returns both the IP of the server where the resolution took place, and the results. After that, there doesn’t seem to be a way to distinguish one line from the other. I needed another way to only return the results.

PS> nslookup subdomain.mydomain.com | Select-String Address

Address: 10.10.10.1
Address: 10.20.30.40

I decided to pipe the command above to the Get-Member cmdlet to see what kind of object the Select-String cmdlet returned. The property that jumped out at me right away was LineNumber — was it really going to be that easy?

   TypeName: Microsoft.PowerShell.Commands.MatchInfo

Name         MemberType Definition
----         ---------- ----------
Equals       Method     bool Equals(System.Object obj)
GetHashCode  Method     int GetHashCode()
GetType      Method     type GetType()
RelativePath Method     string RelativePath(string directory)
ToString     Method     string ToString(), string ToString(string directory)
Context      Property   Microsoft.PowerShell.Commands.MatchInfoContext Context {get;set;}
Filename     Property   string Filename {get;}
IgnoreCase   Property   bool IgnoreCase {get;set;}
Line         Property   string Line {get;set;}
LineNumber   Property   int LineNumber {get;set;}
Matches      Property   System.Text.RegularExpressions.Match[] Matches {get;set;}
Path         Property   string Path {get;set;}
Pattern      Property   string Pattern {get;set;}

Here’s the thing, the output of nslookup is always the same: this on a this line, and that on that line. This is likely why the LineNumber property looked so promising, so quickly. Now that we know we have this property, let’s try and use it. While my first line number guess worked (read, dumb luck), let’s do it wrong first. Consider again our most recent output below.

PS> nslookup subdomain.mydomain.com | Select-String Address

Address: 10.10.10.1
Address: 10.20.30.40

You might think you would want line 3 of our output, but that’s not correct. Even though Select-String has trimmed down the output, the line numbers are all still intact. Look at the very first example at the top of this post. Line 3 is blank — it’s line 5 that we want! Take a look.

PS> nslookup subdomain.mydomain.com | Select-String Address | Where-Object LineNumber -eq 5

Address: 10.20.30.40

If you want to store this as as a string, use the .ToString() method.

PS> (nslookup subdomain.mydomain.com | Select-String Address | Where-Object LineNumber -eq 5).ToString()
Address: 10.20.30.40

And, if you want to remove the word “address,” the colon, and the space, in order to only return the IP address, then you can parse the string by using the .Split() method. The example below splits the string at the space and return the last element — what’s on the right side of the space.

PS> (nslookup subdomain.mydomain.com | Select-String Address | Where-Object LineNumber -eq 5).ToString().Split(' ')[-1]
10.20.30.40

I hope this was helpful for someone. Until next time.