Enabling Legacy Status Icons In Pop!_OS

As we mentioned back in Episode 6, I had installed Pop!OS on my desktop. The design of the Pop!_OS interface is very streamlined and minimal to allow you to focus on things without as many distractions as you’ll frequently see in competing operating systems. That’s pretty awesome, but sometimes I want distractions… namely the ones I get by seeing which applications I have up and running in the background. As you’re probably used to seeing, applications like Dropbox and Discord will drop a small icon somewhere in your OS to let you know the applications are running. For example, by default they’ll appear in the bottom right corner of the screen in Windows and at the upper right corner in macOS which is right next to the clock. In Ubuntu, which Pop!_OS is based on, they’ll also show up next to the clock in the upper-right corner of the screen.

I could live without a Discord icon, but I really wanted one for Dropbox; it’s useful to see the icon change based on the sync status of the service. I did a little bit of digging, and the most challenging part was honestly what search terms to use in order to find the information for which I was hunting. Luckily, it didn’t take long for me to find the official documentation on the matter.

“Ubuntu and previous versions of GNOME Shell supported “status icons” or “AppIndicators” where installed apps could add arbitrary icons to the shell. In GNOME Shell 3.26, this functionality was removed in favor of other APIs.”

The issue isn’t that Pop!_OS doesn’t support status icons, but that it doesn’t support legacy status icons… at least not out of the box. The application gnome-shell-extension-appindicator from the standard repositories will fix this, though. Just install it via:

sudo apt install gnome-shell-extension-appindicator

Once it’s installed, launch it with:

gnome-shell-extension-prefs

Then turn on KStatusNotifierItem/AppIndicator Support. Boom. Okay, not boom. I had to log out and back in first, as noted in the documentation. After that, though, I was able to see my Dropbox icon in all its glory.

Worth it. Stay pink!

Sorting IP Addresses With PowerShell

I was recently attempting to sort a list of IP addresses that I had in a text file. PowerShell is awesome at sorting, so I figured I would use it given that I had nearly 2000 of them. I initially just tried to pipe the contents of the file to the Sort-Object cmdlet:

Get-Content -Path .\ipListFixed.txt | Sort-Object

The results were, suffice to say, lackluster. I ended up with something like this:

10.1.69.1
10.1.69.12
10.1.69.148
10.1.69.149
10.1.69.17

Gross, right? Obviously 10.1.69.17 shouldn’t be after 10.1.69.148 or .149. The issue is that the whole octet isn’t being considered. It’s being sorted like they’re just strings rather than IP addresses; 7 is bigger than 4 so they’re sorted accordingly. PowerShell isn’t really comparing the numbers of 17 to 148, for example, to realize that 17 is actually smaller.

It makes sense; PowerShell can’t assume that the value is an IP address so it’s treating the value like a string instead. This means that the key is to tell PowerShell it’s an IP address so that PowerShell can adjust the way it does sorting. This is possible by casting the values as the .NET Version class. Since I happened to be pulling the IPs from a file, I did the casting within the -Property parameter that I added to the Sort-Object cmdlet:

Get-Content -Path .\ipListFixed.txt | Sort-Object -Property { [System.Version]$_ }

This yields significantly better results:

10.1.69.1
10.1.69.2
10.1.69.12
10.1.69.17
10.1.69.29

Stay pink!

Unusually Pink Updates: Dropbox, Password Managers, and Ad Blocking

This will be one of those weird amalgam posts featuring multiple only mildly-related topics but which are too short to be a post in their own right. I though it would be helpful to provide some updates on a few things that Brandi and I have talked about in some of our past episodes. They’re all tech-related… but you already know that from reading the title.

Dropbox Upgrades and Price Increases

On June 1st, Dropbox added more features to their Plus plan. I’ve been a Plus customer for a couple of years now. It’s less of a “I need to pay for the extra space” situation and more of a “I store some important shit in here and this gives me more peace of mind” situation. The main features from the upgrade, according to the email they sent me, are:

“Double your storage—save everything with 2 TB (2,000 GB).
World-class sync technology—move out-of-date files off your computer’s hard drive and to the cloud with Dropbox Smart Sync.
Dropbox Rewind—roll back accidental changes to any folder, or your entire account, up to 30 days.”

The extra storage is nice, though suffice to say it’s not exactly something I need.

Rewind seems really nice, though. I store a lot of PowerShell scripts in Dropbox, so I could see rewind being useful if I accidentally break one or need to snag an older version for some reason. While I’ve recently been making an effort to check in my bigger, more important scripts with Azure DevOps for version control, smaller ones that I’m the only person likely to use still just go into Dropbox.

Things aren’t all roses and unicorns, though, as the added storage and features come at a cost: $2 USD more per month. This bumps the monthly price up to $12 USD. The good part is that if you go with yearly pricing, you save that $2 a month and pay $120 for the year. I’m actually still on monthly pricing despite having used the Plus service for a few years so I’ll need to move over for sure. While the bonus storage is available now the new pricing isn’t happening for me until July. So before early July I need to swap to yearly billing to avoid paying the extra couple of bucks.

Wired Password Manager Recommendations

In our last episode, Brandi and I spoke a bit about password managers. Right after we recorded that episode Wired published an article all about password managers. The timing seemed perfect to share it. Of the ones Wired recommends Dashlane is the only that I haven’t used. It also makes me feel good that my preferred password manager, 1Password, was Wired’s #1 recommendation.

Speaking of Wired, I love their content but always run into my 5 free articles per month limit. I just happened to see earlier today that they’re doing a deal where you can snag a year’s subscription for just $10. This includes the print editions plus digital content (normally $50 a year) or just digital if you don’t care about print (normally $30 a year.) I was fortunate enough to see it right when they posted to Twitter. I have no clue how long this is running for, but it seems pretty worthwhile if you’re a geek and like tech news. And no… we don’t get anything for promoting this. I just like Wired.

Browser Ad Blocking

Also from our last episode, we discussed how Google was initially thinking about making changes to the webRequest API that would essentially cripple ad blockers. Like we discussed in the episode, after those initial reports and backlash in January Google had backed off a little and said they would think through how this API update should work. At the end of May, though, it came to light that Google still plans to nuke the webRequest API pieces that allow current ad blockers to work… that is unless you’re a G Suite customer.

What’s worse is that these proposed changes seem to be in the open-source Chromium project. So unless Microsoft does some work on their fork, the Chromium-based version of Edge could also be impacted. Suffice to say this gives me some significant pause on my previously mentioned plans to buy a new Chromebook. I’m now re-evaluating what I should do for my laptop situation. And if you haven’t used Firefox Quantum recently, now might be a great time to check it out.

PowerShell: Export Non-Standard and Multi-Value AD Attributes to CSV

I’ve recently been spending a lot of my time at work doing PowerShell scripting for a project that’s currently underway. While working on a bit of code late last week I ran into two interesting problems that I had yet to really stumble across despite doing heavy PowerShell scripting against Active Directory for nearly a decade now.

Exporting Non-standard Attributes To CSV

My first issue was that I needed to export some non-standard attributes from contact objects in AD to a .csv file. When I say “non-standard” I don’t mean that we’ve done a custom schema extension or anything like that. Instead, I simply mean that the AD PowerShell module only wants to include certain attributes when exporting AD objects to a .csv file. For example, if I run Get-ADObject -Properties * against a particular contact object and simply let the output dump to my shell, I see all of the attributes I expect including stuff like givenName and sn. However, if I run the exact same cmdlet but pipe the result to Export-Csv rather than sending it to the shell I will not have all the same attributes; ones like givenName and sn will now be missing. That’s a problem.

Storing Mutli-Value Attributes In a CSV

The other problem was that one of the attributes I needed is proxyAddresses. This is a multi-value attribute as contacts could very likely have multiple proxy addresses associated with a particular mailbox. They may have an alias, x500 addresses, etc. If you use PowerShell to pull this information from AD and dump it to the screen you’ll see the expected proxy address information. If you call GetType() on the proxyAddresses attribute you’ll see it listed as an array. That’s why if you export a contact to a .csv file and include proxyAddresses, the value for each contact in that particular column will simply read:

Microsoft.ActiveDirectory.Management.ADPropertyValueCollection

PowerShell isn’t sure what to do with a multi-value attribute as far as the .csv file goes so it stores the data type. This is also a problem!

The Solution

My solution to this was the following. Note that it’ll be easier to view the Gist for it.

# Get the objects with the required attributes and storing proxyAddresses properly in the .csv file.
Get-ADObject -Filter { objectClass -eq "contact" } -Server myserver.mydomain.net -SearchBase "OU=Contacts,DC=mydomain,DC=net" -SearchScope OneLevel -Properties name,givenName,sn,displayName,telephoneNumber,proxyAddresses,targetAddress,mail,mailNickname,company,department,l,physicalDeliveryOfficeName,postalCode,st,streetAddress,title | Select-Object name,givenName,sn,displayName,telephoneNumber,targetAddress,mail,mailNickname,company,department,l,physicalDeliveryOfficeName,postalCode,st,streetAddress,title,@{name="proxyAddresses"; expression={$_.proxyAddresses -join ";"}} | Export-Csv -Path .\sample.csv -Encoding ASCII -Append -NoClobber -NoTypeInformation

# Shows how to then use the proxyAddresses attribute in the future.
$allContacts = Import-Csv -Path .\sample.csv
foreach($singleContact in $allContacts) {
    $proxyAddresses = $singleContact.proxyAddresses.Split(";")
}

The first thing I needed was to get the properties I actually needed as opposed to just the ones PowerShell felt like including due to the object type. The solution was to:

  1. Specify all of the attributes I wanted in -Properties to ensure they would be available.

  2. Pipe the AD object to Select-Object and then re-specify each of the properties I wanted.

This works because PowerShell is selecting the attributes to include in the .csv file based on the type of object. Select-Object takes whatever comes through the pipeline, though, and makes a brand new, generic object from it. That object will include any properties from that original object that you specify, hence why I tell it the exact listing of properties that I need again.

This leads to the solution to the second problem which is what to do for proxyAddresses. PowerShell allows for the use of an expression to parse together a new property. In this instance the expression is to take the existing proxyAddresses array and -join it into a string. Each of the items in the array are separated by a semicolon. If a contact has the following proxy addresses, for example:

SMTP:pretty@unusually.pink
smtp:awesome@unusually.pink

Then the property in the .csv file will be stored as:

SMTP:pretty@unusually.pink;smtp:awesome@unusually.pink

You could pick any character for the delimiter that you want as long as it isn’t used in other data that you’re storing.

In this instance my goal was to take the exported data, re-import it, and then create contacts in a different AD forest. When creating a new object AD is expecting an array for the proxyAddresses attribute. A string with a random delimiter won’t do it. That’s where the second part of the example comes into play. If I’m looping through all of the data stored in the .csv file I can recreate the array of proxy addresses by splitting the string on my delimiter (in this case a semicolon) and assigning the result to a variable. That variable will be an array which can then be used to popular proxyAddresses when running New-ADObject