Monthly Archives: December 2015

PowerShell Resolutions 2016

I wrote about my Windows PowerShell resolutions last year after a Tweet by Boe Prox. In what may become a tradition, he’s started up the conversation up again, over at Reddit. If you’re not convinced to make a list for yourself, then let me recommend you do. Knowing I had written and shared a list of resolutions, and that people may have read it, was enough motivation to stick to what I could and update my progress during the year. My 2015 resolutions are listed in the first link above, and were an overall success.

So, 2016. First and foremost I’m out to be a DSC genius twelve months from now. I’ve been spending a decent amount of time adding new DSC resources, modifying configuration scripts, creating new MOFs and having target nodes pull those. While this is in test, I don’t see why I wouldn’t have rolled this out to production at some point in 2016.

It’s a fair bet to assume that I’ll continue to read, and help, on the PowerShell forums at PowerShell.org, Reddit, and Microsoft Technet. Instead of linking those individually, you can find their links on my about page. If you want to learn more about PowerShell, then I recommend you read these. It’s an easy way to pick up things you might not learn otherwise. In addition, you might start to find yourself helping others sooner, or later. It happened to me.

I’m going to read PowerShell in Depth quite soon, and PowerShell in Action, when the newest version ships in the spring. I really don’t mind reading what I already know for review and solidification of concepts. Plus, I want to be able to recommend these titles to people in situations where someone would benefit from them over some of the other PowerShell titles I’ve read. I can’t wait to get started.
Update: It’s not even 2016, and I went ahead and started PowerShell in Depth. I’ve read up through Part 1 of the book and I already appreciate the deeper level content. As someone that read the Month of Lunches book, I can easily spot where the authors provided additional information.

Let’s see, what else? How about I get my first module up on the PowerShell Gallery. I can do that in 2016, once I decided what to add, or what to first write and then add.

Almost as soon as I posted this, it occurred to me: Nano Server. I expect that I’ll take some time this year to become proficient with this technology.

Find the Account that Starts a Service

There was an email I wrote to a team member last week. The point behind it was to help the team member determine what service(s) might be running under a certain account. The Get-Service cmdlet has never provided this functionality, so I mentioned that they use the Win32_Service WMI class (with Windows PowerShell, of course).

This suggestion led to me write and send them a list of command examples to include local vs. remote computers, pulling computer’s from a text file and Csv file, and using Active Directory. It seemed like a fairly solid list, and so I thought it should be posted here. I won’t bother including any output, because it’s fairly easy to figure out what’s going to be returned — the name of the service, the account used to start/run the service, and the remote computer name, in some of the commands that run against remote computers.

This first example is how to run the command against the local computer. This will return all the services on the local computer to include the account that is used to start the listed service.

PS> Get-WmiObject -Class Win32_Service | Select-Object Name,StartName

This example shows how to run the same command above, against a single remote computer. The only difference is the addition of the -ComputerName parameter and the Server01 parameter value.

PS> Get-WmiObject -ComputerName Server01 -Class Win32_Service | Select-Object Name,StartName

In this example, we run the same command above, except we do run it against two computers. In order to know which computer returned which result, we include the PSComputerName property.

PS> Get-WmiObject -ComputerName Server01,Server02 -Class Win32_Service | Select-Object PSComputerName,Name,StartName

Here’s one way to use a text file. The Get-Content cmdlet executes first, because it’s in parenthesis. The results of this command are then provided to the -ComputerName parameter.

PS> Get-WmiObject -ComputerName (Get-Content -Path C:\computers.txt) -Class Win32_Service | Select-Object PSComputerName,Name,StartName

This example does the same thing as the command above; however, it does so by piping the results of the Get-Content cmdlet to the ForEach-Object cmdlet. Within each iteration of the foreach loop, it runs the Get-WmiObject command. In testing, there wasn’t much different in the time it took to complete this example when compared to the last one.

PS> Get-Content -Path C:\computers.txt | ForEach-Object {Get-WmiObject -ComputerName $_ -Class Win32_Service | Select-Object PSComputerName,Name,StartName}

This next example utilizes a Csv File. In a Csv file, we have (column) headers; therefore, we need to indicate to PowerShell the column we’d like to use. Let’s assume we have a Csv with three columns of data with the headers Location, NameOfComputer, and Year. We’ll need to make sure we’re instructing our command to only use the data in the NameOfComputer column.

PS> Get-WmiObject -ComputerName ((Import-Csv -Path C:\computers.csv).NameOfComputer) -Class Win32_Service | Select-Object PSComputerName,Name,StartName

Here’s the same example as above, but this one uses a pipeline and ForEach-Object cmdlet, much like we did with the text file. While there’s little difference in the time it takes to complete, I would recommend that we don’t use a pipe when it’s not necessary, or when it’s doesn’t give us an advantage.

PS> Import-Csv -Path C:\computers.csv | ForEach-Object {Get-WmiObject -ComputerName $_.NameOfComputer -Class Win32_Service | Select-Object PSComputerName,Name,StartName}

Let’s incorporate Active Directory (AD), since it’s another place where we can get computers. This first AD example returns all the computers from a specific Organization Unit (OU) and runs them through the Get-WmiObject cmdlet. As in previous examples, this command will return all the values before it provides them as the value to the -ComputerName parameter.

PS> Get-WmiObject -ComputerName ((Get-ADComputer -Filter * -SearchBase 'OU=Engineering,OU=Workstations,DC=mydomain,DC=com').Name) -Class Win32_Service | Select-Object PSComputerName,Name,StartName

In my coworker’s situation, one of the computers in the OU was down, so we needed a way to filter around that problem. Here’s two ways to do that; however, the second option is the better of the two. If you’ve never heard it before, hear it now: filter as close to the left of your commands as possible.

PS> Get-WmiObject -ComputerName ((Get-ADComputer -Filter * -SearchBase 'OU=Engineering,OU=Workstations,DC=mydomain,DC=com' | Where-Object {$_.Name -ne 'Server22'}).Name) -Class Win32_Service | Select-Object PSComputerName,Name,StartName

PS> Get-WmiObject -ComputerName ((Get-ADComputer -Filter {Name -ne 'Server22'} -SearchBase 'OU=Engineering,OU=Workstations,DC=mydomain,DC=com').Name) -Class Win32_Service | Select-Object PSComputerName,Name,StartName

 

Prep computers.txt File for HTA

Last week, I opted to share a couple of old HTAs I had written. HTAs are HTML Applications and allow administrations the ability to create a graphical interface for their scripts. It’s an older technology and not something I still write, or use. Even so, I wanted to share them with the community. As they’re not Windows PowerShell-related, I thought I should circle back on that post and incorporate some PowerShell.

The second of the two HTAs I shared was called Remote Desktop Assistant (download link: RDAssistantv2.1 (9308 downloads ) ). Its purpose is to allow a user to select a computer description from a list and open Remote Desktop to connect to that computer. I know, I know, this goes against all things PowerShell, but it was written a long time ago. The HTA has a requirement for an external text file called computers.txt that stores computer descriptions and computer names / IP addresses, such as we have in the list below. It’s a computer description, a semi-colon, and the computer name or IP address.

computer1;10.10.10.5
computer2;dns1.mydomain.com
computer3;10.10.10.9

We can make use of Active Directory and PowerShell to create this list and subsequent text file, so we don’t have to do it manually. In fact, once you had your code written you could schedule it to ensure the computers.txt file was as accurate as the last time the scheduled task ran. While the preferred way to do this would be to store host names (at least in my opinion), I’ll show examples of collecting the IP addresses, too.

In the first example, we’ll pull all of our servers from a single Organizational Unit to return the names and DNSHostNames.

PS> Get-ADComputer -Filter * -SearchBase 'OU=Servers,DC=mydomain,DC=com' -Properties DNSHostName | Select-Object Name,DNSHostName

Name                                                        DNSHostName
----                                                        -----------
SQL01                                                       SQL01.mydomain.com
SQL02                                                       SQL02.mydomain.com
SQL03                                                       SQL03.mydomain.com
SQL04                                                       SQL04.mydomain.com

In this example, we return the names and IP addresses.

PS> Get-ADComputer -Filter * -SearchBase 'OU=Servers,DC=mydomain,DC=com' -Properties IPv4Address | Select-Object Name,IPv4Address

Name                                                        IPv4Address
----                                                        -----------
SQL01                                                       10.10.10.30
SQL02                                                       10.10.10.31
SQL03                                                       10.10.10.32
SQL04                                                       10.10.10.33

While these are the results we want, we need to get them into the proper format. We’ll do this by looping through each result and concatenating the two properties with semi-colon in between. To do this, we do not need to use the Select-Object cmdlet to return the Name and IPv4Address, or DNSHostName.

PS> Get-ADComputer -Filter * -SearchBase 'OU=Servers,DC=mydomain,DC=com' -Properties IPv4Address | ForEach-Object {"$($_.Name):$($_.IPv4Address)"}
SQL01;10.10.10.30
SQL02;10.10.10.31
SQL03;10.10.10.32
SQL04;10.10.10.33

With the host name set, we’ll take this one step further and create our computers.txt file.

PS> Get-ADComputer -Filter * -SearchBase 'OU=Servers,DC=mydomain,DC=com' -Properties DNSHostName | ForEach-Object {"$($_.Name):$($_.DNSHostName)"} | Out-File -FilePath C:\computers.txt
PS> Get-Content -Path C:\computers.txt
SQL01;SQL01.mydomain.com
SQL02;SQL02.mydomain.com
SQL03;SQL03.mydomain.com
SQL04;SQL04.mydomain.com

Chances are good that if you use the DNSHostName, you’re never going to have an Active Directory computer object returned without one. The same can’t be said if you use the IPv4Address, as this property is created at the time the results are returned (it queries DNS). Think about it, have you ever seen an IPv4Address property inside Active Directory Users and Computer when viewing a computer object? The DNSHostName option might be the better option, but I’ll leave that up to you.

Two Old HTAs: LoggedOnUser and Remote Desktop Assistant

There was a recent Windows PowerShell forum post that discussed HTAs. Due to that, I thought I would discuss a couple old HTAs I wrote and include their download links. Many people may not know it, but I was once a VBS aficionado. I had a task to set some registry settings back in 2005, or 6, and ended up staring some VBS examples right in the face. I was instantly hooked. I starting writing all kinds of things, and today I’m going to share two of my old HTAs — a couple favorites.

HTAs are HTML Applications. They allowed script writers, such as myself, the ability to create GUIs for their scripts. I suddenly had a way to hand over scripts in an easy to use fashion for users, and other IT personnel.

Funny story, but when Windows PowerShell — a.k.a Monad — was first introduced, I was excited at first, but then I was pissed (upset, not drunk). I had put so much time and effort into VBS, that moving to something else was upsetting. I’ve gotten over that now; I would need an extremely large pay day, to write and/or troubleshoot any VBS.

The first of the two HTAs I’ll share is called LoggedOnUser (1.6). Its original purpose was to determine who was logged on to a specific computer. Here’s what the HTA looks like when it’s first opened.

script-sharing-two-old-htas-loggedonuser-and-remote-desktop-assistant-2015-01

While you may not know what to do right away, there’s a tooltip that displays when you hover over the textbox, that reads, “Enter computer name, IP address, cmd or exit.” If someone entered “cmd” and pressed Enter, it would open the command prompt. I guess that seemed important at the time. If you entered “exit” and pressed Enter, then the HTA would close. Hopefully no one had a computer named cmd or exit! I wrote this for myself, so I assume I wasn’t worried about that possibility. If a computer name or IP is entered, it would attempt to connect over the network (using VBS and WMI), and populate three fields: Computer (as in the computer’s name), the currently logged on user as domain\user, and the full domain. Here’s an example:

script-sharing-two-old-htas-loggedonuser-and-remote-desktop-assistant-2015-02

After some time had passed, I decided to do more with this daily used HTA. I added a drop down menu that would perform different tasks, such as open C$, open Computer Management, and start a Remote Desktop Connection to the listed computer.

script-sharing-two-old-htas-loggedonuser-and-remote-desktop-assistant-2015-03

It was a fun project and the HTA was actively used from 2007 to probably 2013, by myself and at least one other IT shop. In my 1.5 version (one previous to this 1.6 version), there was a drop down option that opened up an inventory system to the listed computer’s inventory webpage. The inventory system had been built using a .vbs start up script deployed via Group Policy. It would collect computer information (including the logged on user), and write it to an Access database back end (yes, Access). Classic ASP was used for the web front (yes, classic ASP). Good times. I can say this: learning VBS made learning classic ASP extremely easy.

You can download this HTA here: LoggedOnUserv1.6 (6773 downloads )

The second HTA I’ll share was an amazing test of my patience. I’d like to thank Tool’s 10,000 Days for getting me through it.

I called this one Remote Desktop Assistant and its purpose was to store computer descriptions and matching IP addresses, or computer names. Choosing a computer from the list would allow a user to start a Remote Desktop Connection. This first screen shot shows the HTA when there are no stored computers. Let’s add one.

script-sharing-two-old-htas-loggedonuser-and-remote-desktop-assistant-2015-04

This image below, is what it looks like when it’s storing a computer for us. It stores this information in a computers.txt file in the same location as the HTA. Move the HTA and not the text file, and no computers will be listed, and the HTA will create a new computers.txt file. Yes, it’s creates this file if it can’t find one. With a single computer entered, such as we have below, the text file would contain one line that reads: Server01;10.10.10.35. It’s two strings with a semi-colon delimiter.

script-sharing-two-old-htas-loggedonuser-and-remote-desktop-assistant-2015-05

The server (Server01), in the image above was added by entering a description in the “Computer Description” textbox, and a corresponding computer name or IP address in the “IP Address or Computer” text box. When a user clicks on the computer in the left, it populates the the two textboxes and changes the “Choose Computer” button to a “Launch Remote Desktop” button. Do you see all this fanciness!?

script-sharing-two-old-htas-loggedonuser-and-remote-desktop-assistant-2015-06

If you press “Launch Remote Desktop” then it will do just that. The three bottom buttons: About…, Notes, and Feedback, offer some additional information about the HTA. It’s nothing monumental, but I was pleased with my ability to resize the form and replace the text in the lower area. The Hide button closes the lower, informational panel. Take a look below to see what I mean.

script-sharing-two-old-htas-loggedonuser-and-remote-desktop-assistant-2015-07

script-sharing-two-old-htas-loggedonuser-and-remote-desktop-assistant-2015-08

Well, that was a fun trip down memory lane. Who knows, these might actually be helpful for someone. One of the things I did, which I may share in a future post, was rewrite the LoggedOnUser VBS/HTA using PowerShell. There’s no GUI, but it does everything that HTA does, way faster, and with much less code. As you check these out, please keep in mind I wrote these around 2005 – 2007, or 8. Cheers!

You can download this HTA here: RDAssistantv2.1 (9308 downloads )

Update: Use PowerShell and Active Directory to create your computers.txt file: http://tommymaynard.com/quick-learn-prep-computers-txt-file-for-hta/.