I consider myself fairly decent at writing scripts for windows stuff. Mostly in batch where I would consider myself a 9/10, and in vbscript where I would consider myself a 6/10. Of course the windows world is moving to powershell, and I have been slowly working on learning it. (It does help that my good buddy Hal is a powershell guru.) What usually happens though is I get in a hurry for something and can’t be slowed down to learn something new. Luckily since I have changed jobs, I have more time to actually learn things instead of putting out fires full time.
So anyway, until now, most of my powershell scripts were just copying and pasting various bits from others and putting them together just to make things work, but yesterday I found a bit of a challenge.
We have an application here at work that allows a limited number of user licenses, and strangely enough, it keeps a license open for a user as long as they have the windows share open. (Don’t ask me.. this is what I was told and I’m accepting it at face value.) There’s no way to expire the license if they have the share open, and it can stay open for a number of reasons. What happens is that over time we get these left open and run out of licenses. The business has agreed that anyone that’s idle more than 2 hours can be forcibly removed from the application by removing their session to the share.
We can see if these are actually in use by opening up the computer management MMC and going to shared folderssessions. Once we sort by idle time, we can see that there are a number of sessions with more than 2 hours of idle time. (Note: In the screenshot below I have hidden the usernames and computernames.)
You can also see the same bit of info by running “net session” from a command prompt.
After some googling, I decided that wmi would be the way to go, and I immediately found the Win32_ServerConnection class. This looked like it, but if you want to see the idle time.. guess what? While everything else is, this one is not exposed. So no dice.
After scratching my head for a bit, I decided that using net session would be the way to go, and we could manipulate the output in order to get what I was after. I messed with powershell doing this for a bit and I wasn’t making any progress. Hal was on vacation in Disney world, and my other script buddy Marcus was at the Microsoft MVP summit, so I couldn’t ask him either. So I got nowhere for a bit and had to resort back to batch.
What I did was take the output of net session and use logparser.exe with a custom input format. This was a pain because the fields aren’t delimited by anything other than spaces. When I set the idle time field to date, it thought a 00:00:00 was Jan 1, 1900, so basically I was looking for a date greater than 2AM on Jan 1, 1900. Using that I was able to get the list of computers and run “net session \%strcomputer /delete”. This worked, but it was ugly, and I’m not even going to bother posting the script, because this post is about powershell.
Yesterday I decided that I wanted to get this working in powershell as much as I can, and while searching, I ran across the Win32_ServerSession Class, and was surprised to find that it included IdleTime. Nice! (why isn’t this in with the others, Microsoft? And why couldn’t I find it by searching on their site? I ran across this on page 6 of a google search.) Of course there are no methods exposed here, so I was back to the drawing board on ending the session. Eventually I had to give up because there doesn’t seem to be an equivalent for “net” inside powershell.
Based on this, I went ahead with the script as it is now, here it is:
$strComputer = “%computername%”
$tool="net.exe"
$cmdLine = "session \$computer /delete"
$idleuser=get-WmiObject Win32_ServerSession -computername $strComputer | where-object {$_.IdleTime -gt 7200} | where-object {$_.UserName -ne "SERVICEACCOUNT"} | format-table ComputerName -auto
$idleuser
foreach($computer in $idleuser) {invoke-expression "$tool $cmdLine"}
write-output BIG BANG
In the end this was a pretty easy script, all I am doing besides setting up the variables is grabbing the info via wmi, then looking for IdleTime being greater than 2 hours or 7200 seconds, and then excluding the service account. Output what’s left to a table. I then print that to screen for my own sanity, and run a for loop against the computername using the command line of net session that I set up earlier.
Now it’s done, the script works, I know a bit more about powershell, and life is good. Next!