Setting up my PowerShell profiles

There comes a time in every programmer’s life when s/he has to strike out on his/her own, writing new code (instead of typing in examples from books / websites). That time has come now for me with regards to PowerShell.

But first, I have to set up my working environment.

Here at work, we have a common (i.e., shared) network directory on our Production resource server. There were no PowerShell utilities in the directory (probably because I think I’m the first person to do anything serious with PowerShell here, with the possible exception of the IT guys – and they don’t use the Production resource server).

However, it occurred to me that that common directory (call it N:\common\utils, because that’s not its name) would be a good place to put modules meant to be shared.

How do I tell PowerShell to look for modules there, without having to specify this every time I start PowerShell?

For now, I just:

  1. created a PS subdirectory in N:\common\utils (PS for PowerShell, of course)
  2. Started PowerShell on my PC and created a profile file in the $profile directory (per Recipe 1.6 from the Windows PowerShell Cookbook):
    New-Item -type file -force $profile
  3. edited the profile file using Notepad.exe:
    notepad $profile
  4. and added a line to add the common directory to the PSModulePath environment variable:
    $env:PSModulePath += “;N:\common\utils\PS”
    (the leading semicolon is the profile path separator)
  5. exited notepad, saving $profile on the way out.

 

Now, whenever I start PowerShell, the $profile runs and adds the PS shared folder to the module search path.

To do the same thing (less step 1) for the Windows PowerShell ISE, I consulted Microsoft Technet article How to Use Profiles in Windows PowerShell ISE, which suggests wrapping the New-Item in step 2 in an if statement to prevent overwriting an existing profile, and using the ISE to edit the resulting profile file:

  1. (PS subdirectory already created in N:\common\utils)
  2. Started the PowerShell ISE and created a profile file in $profile:
    if (!(test-path $profile)) {New-Item -type file -path $profile -force}
  3. edited the profile file (using the ISE editor):
    psEdit $profile
  4. and added the same line to add the common directory to PSModulePath:
    $env:PSModulePath += “;N:\common\utils\PS”
  5. then closed the ISE editor tab, saving the ISE $profile file on the way out

 

Now I just have to figure out modules and module manifests…

Automating web browsing using PowerShell

A lot of our Production Quality Control (QC) operations where I work require checking that data has been uploaded to one of our websites, using either one of our internal tools, or our backdoor access to one of our customer-facing sites. This is all right when we’re checking a couple of customer jobs, but gets tedious VERY quickly for routine QC of dozens or hundreds of customer jobs.

A web app works well as a manual tool (“enter text to be searched for in this box, click Search, click the link for desired item in the list of items matching your search term…”), but our internal tools and customer-facing sites were never designed to be scripted.

For a while, when I was working with more cross-platform scripting languages, I was looking at Selenium. Selenium allows you to control popular web browsers from a number of programming languages, including Python, Ruby, and C# – but not directly from PowerShell. It would be possible to write my own PowerShell wrapper for C# to control Selenium, but I don’t have any experience extending PowerShell with C#, and since we’re not a C# shop, I think that would be very fragile from a long-term maintenance standpoint.

Anyway, unlike the typical Selenium application, our Production QC ops aren’t testing a single web app across multiple browsers. We’re searching for a multitude of data items, but we only have to find each one once, in a single web browser. A more robust solution would be to use something more native to PowerShell to control a single browser – which could even be Internet Explorer (perish the thought!).

I Googled “powershell web browser automation” and came up with a number of possibilities.

Web UI Automation with Windows PowerShell, is an MSDN article from 2008 and talks about using COM to control Internet Explorer, which is something I’ve dabbled in using VB Script. My first experiment with the method wasn’t successful, though, so I looked for troubleshooting info for COM in my handy copy of Windows PowerShell in Action. As it happens, the book illustrates COM with an example of “…a COM-based tool to help manage…browser windows,” so the book probably offers a more fertile field for further research.

A post on StackOverflow then led me to WatiN – Web Application Testing in .Net. WatiN allows control of Internet Explorer AND Firefox, so it might be even better than using COM.

Find subfolders that lack a given file(name)

Our processing automation at work creates a number of files during processing. One way we can tell when the automation hasn’t completed successfully is when the processed files directory has been created, but the files that are created at the end of processing are missing from the directory.

Here’s a PowerShell script fragment to identify subfolders (two levels down) that lack a given file (target.txt in this example) :

PS > Get-ChildItem |
>>   ForEach-Object {
>>     Set-Location $_
>>     Get-ChildItem |
>>       Where-Object {!(Test-Path $_\target.txt)}
>>     Set-Location ..
>> }
>>

And here’s a one-liner version of the above:

PS > ls | %{ cd $_ ; ls | ?{!(test-path $_\target.txt)} ; cd ..}

It’s not perfect – if it encounters a file (rather than a subdirectory) one level down, it attempts to Set-Location to that filename and throws an error (because you can’t Set-Location to a file, only a folder). However, it seems to find all the folders missing the target.txt file before it attempts to Set-Location to that file.

PowerShell – Get-WmiObject vs. Get-CimInstance

A recent post on the Hey, Scripting Guy! blog showed how to use PowerShell to find a network adapter’s MAC address. The post provided two ways to get the information using WMI:

Get-WmiObject win32_networkadapterconfiguration | select description, macaddress

Get-CimInstance win32_networkadapterconfiguration | select description, macaddress

I wondered about the difference between GetWmiObject versus Get-CimInstance. Happily, while exploring older Hey, Scripting Guy! posts, I found one about simplifying PowerShell scripts that addressed the difference(s):

One of the first changes I make to a script, if I can, is I change Get-WmiObject to Get-CimInstance. Since Windows PowerShell 3.0, I can use Get-CimInstance. It is faster and more robust, and it permits lots of cool things for retrieving data (such as using Cim-Sessions).

Since most of our servers here are running PowerShell 2.0 right now, it will be a while before I can routinely use Get-CimInstance instead of Get-WmiObject — but it’s something for me to keep in mind for the future.

Scriptify – A navigation aid for SharePoint 2013 PowerShell Cmdlets

Via yesterday’s Hey, Scripting Guy! blog –

Scriptify – A navigation aid for SharePoint 2013 PowerShell Cmdlets is a web-based reference for PowerShell cmdlets related to SharePoint 2013. The cmdlets are divided into 36 categories – clicking on a category’s button takes you to a page of buttons to access the invidual cmdlets in that category. Clicking on a cmdlet’s button takes you to a page with parameters for the cmdlet and a link to its Technet homepage.

Accessing the Outlook Inbox – ‘NoCOMClassIdentified’ error

We get a lot of email where I work. A metric butt-ton.

One of the things I’d like to be able to do is access that email programmatically, in order to extract production processing reports for further analysis.

As a first step, I went looking for a way to access the Inbox using PowerShell. I found a post on Microsoft’s Hey, Scripting Guy blog: Use PowerShell to Data Mine Your Outlook Inbox.

There was just one problem – when I tried the steps to access the Inbox, I got a major error:

PS C:\Windows\system32> add-type -assembly “Microsoft.Office.Interop.Outlook”
PS C:\Windows\system32> $olFolders = “Microsoft.Office.Interop.Outlook.olDefaultFolders” -as [type]
PS C:\Windows\system32> $outlook = new-object -comobject outlook.application
new-object : Retrieving the COM class factory for component with CLSID {0006F03A-0000-0000-C000-000000000046} failed due to the following error: 80080005 Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE)). At line:1 char:12 + $outlook = new-object -comobject outlook.application + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ResourceUnavailable: (:) [New-Object], COMException + FullyQualifiedErrorId : NoCOMClassIdentified,Microsoft.PowerShell.Commands.NewObjectCommand

I searched for “NoCOMClassIdentified” and found a couple of references. I finally found one (I don’t have the link, alas) that helped me realize the problem was that I was running it from a PowerShell session that I’d opened as Administrator (for teh POWER!!!).

When I opened PowerShell as myself, I was able to complete the sequence to access the 60,000+ messages in my Inbox (did I mention we get a LOT of email here?), and use a quick pipe to Where-Object to extract just the emails I sent to myself:

PS P:\> Add-Type -Assembly “Microsoft.Office.Interop.Outlook”
PS P:\> $olfolders = “Microsoft.Office.Interop.Outlook.olDefaultFolders” -as [type]
PS P:\> $outlook = new-object -comobject outlook.application
PS P:\> $namespace = $outlook.GetNameSpace(“MAPI”)
PS P:\> $folder = $namespace.getDefaultFolder($olFolders::olFolderInBox)
PS P:\> $folder.items | Select-Object -Property Subject, ReceivedTime, Importance, SenderName |
>>  Where-Object {$_.SenderName -like “Spurlock*”}Subject ReceivedTime Importance SenderName
——- ———— ———- ———-
How to send an email from … 10/23/2014 7:01:29 PM 1 Spurlock, Edward (Austin)
RE: How to send an email f… 10/23/2014 7:06:15 PM 1 Spurlock, Edward (Austin)
PowerShell script to updat… 10/28/2014 6:17:21 PM 1 Spurlock, Edward (Austin)
RE: PowerShell script to u… 10/28/2014 6:25:15 PM 1 Spurlock, Edward (Austin)

Accessing email through Outlook works, but according to Bill Long’s Exchange Blog, using the Exchange Web Services (EWS) Managed API for PowerShell scripting offers a number of advantages. For one, you can access Exchange data from a system that does not have Outlook installed. Another advantage is being able to do “ranged retrievals” – accessing a subset of the data on each retrieval, rather than having to pull everything down at once and sort it out (as I did with Where-Object).

Happy Birthday, Windows!

Microsoft Interface Manager – excuse me, Windows 1.0 – was introduced to the world on November 10, 1983.

Version 1.0 wasn’t actually released to users until 1985, but Bill Gates showed the first version two years earlier at the Plaza Hotel in New York City.

In 1983, I was still trying to be the next great bicycle racer. By late 1985, I’d quit bicycle racing and started to ask myself what I would do next. I decided on electronic music (I should have gone back to college then, instead of waiting a couple of years) and bought my first keyboard (an inexpensive consumer-grade Casio) that year. I bought an Akai AX-80 analog hybrid synth and an Atari ST 520 in 1986, and started getting involved in the local Atari user group.

I bought a Zenith all-in-one PC that ran MS-DOS from floppies in 1988 (1987? 1989?), but I did a lot more with the Atari. My earliest memory of Windows was the announcement of Windows 3.0 in 1990, which happened at the same time as a tech show in Austin where our Atari user group set up a multiplayer MIDI Maze game. (MIDI Maze was an early “first-person shooter” (FPS) game that used the built-in MIDI ports on the Atari ST to network multiple machines)

I didn’t actually work on Windows machines until I started work at Dell in 1995. I started training in tech support the week before Windows 95 was released on August 24, 1995 – but I and the other first-level techs in my class didn’t get to use Win95 until 1996. My first Windows was Windows 3.1.

Doctor Who fans have a saying – “You always remember your first Doctor.” Similarly, I will always remember Windows 3.1 (but not fondly).

Business Insider has a retrospective on Windows through the years – that unfortunately neglects to mention Windows NT 3.51, Windows NT 4.0 and Windows 2000. It’s as though the first part of my tech career never existed.