Wednesday, September 10, 2014

Making those one liner scripts

Hey PowerShell users, do you love to script, but sometimes find yourself wishing that you just had a one liner to use instead of needing to copy or remotely execute a .ps1 file?

I was emailing back and forth with some colleagues at work recently, and one of our brilliant engineers had sent out this script to find the domain controller in the "closest" site that had the lowest latency. I don't know if he wrote it (he is certainly capable) or found it, but we all found it very useful:

 
$ADSite = [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite().Name
$servers = Get-ADDomainController -Filter  {Site -eq $ADSite}
$DCListObject = New-Object psobject
$DCListObject | Add-Member -MemberType NoteProperty -Name HostName -Value $null
$DCListObject | Add-Member -MemberType NoteProperty -Name QueryTime -Value $null
$DCListObject | Add-Member -MemberType NoteProperty -Name Latency -Value $null
$results = @()
foreach ($server in $servers) {
    $DC = $DCListObject | Select-Object *
    $latency = Test-Connection -ComputerName $server -Count 1
    $querytime = Measure-Command -Expression { Get-ADObject -Server $latency.IPV4Address -LDAPFilter "(&(&(objectCategory=Person)(objectClass=User))(sAMAccountName=REMOVED*))" -ResultSetSize 1 -ErrorAction SilentlyContinue}

    $DC.HostName = $server.HostName
    $DC.QueryTime = $querytime.TotalSeconds
    $DC.Latency = $latency.ResponseTime

    $results += $DC
}
$results | sort QueryTime | ft HostName,Latency,QueryTime -AutoSize

Many remarks were made about the usefulness and coolness of the script, with the addition of one smart alecky response: "It's garbage. Make it one line :-)". This seems to be a running joke here.

Having just spent the last 16 months with a company full of penguin lovers at my last position, I responded with "Challenge accepted ;) maybe", even though I had not been the one challenged. About 8 minutes later (according to my email client), I sent the following back to the group:

$ADSite = [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite().Name ; $servers = Get-ADDomainController -Filter  {Site -eq $ADSite} ; $DCListObject = New-Object psobject ; $DCListObject | Add-Member -MemberType NoteProperty -Name HostName -Value $null ; $DCListObject | Add-Member -MemberType NoteProperty -Name QueryTime -Value $null ; $DCListObject | Add-Member -MemberType NoteProperty -Name Latency -Value $null ; $results = @() ; foreach ($server in $servers) {$DC = $DCListObject | Select-Object * ; $latency = Test-Connection -ComputerName $server -Count 1 ; $querytime = Measure-Command -Expression { Get-ADObject -Server $latency.IPV4Address -LDAPFilter "(&(&(objectCategory=Person)(objectClass=User))(sAMAccountName=REMOVED*))" -ResultSetSize 1 -ErrorAction SilentlyContinue} ; $DC.HostName = $server.HostName ; $DC.QueryTime = $querytime.TotalSeconds ; $DC.Latency = $latency.ResponseTime ; $results += $DC} ; $results | sort QueryTime | ft HostName,Latency,QueryTime –AutoSize

Worked great!

Two things, though. First, sure it's nice to be able to paste a one liner like this into PowerShell and run it with no need to create, save and possibly copy paste a .ps1 text file somewhere. But, secondly, who wants to try to decipher that hideousness?

In case it is not obvious to the reader, all I did in this case was, mostly, to separate each line in the script from the next one using a semicolon. The result is ugly but condensed to a single line that can be stored in your script repository for copy/paste use at any time. Don't ask your developers to look at it though, unless you enjoy that quizzical-what-kind-of-nonsense-am-I-looking-at expression. One other potential bad thing I noticed was that this one liner consistently ran a little slower than the .ps1 script.

Just goes to reinforce the old saying, "Just because you can does not mean you should."

But sometimes the question of "can" is just more fun.


"So that's your ambition? Script writing?" -- Mr. Fisher
 "Yes, it always has been." -- Billy



- Peter Trast, MCITP EA, MCITP DBA, MCT LinkIn with Peter

Monday, September 8, 2014

Windows "unmovable" files CAN be moved

I recently had the pleasure of trying to shrink a volume to allow enabling of BitLocker, only to be informed that I had 0 megabytes of space available for shrinking. Since the 278 Gigabyte drive had about 90% free space, this was a bit shocking, especially considering that I had just installed the operating system a few days earlier. But don't punch the screen before you have a gander at the rest of this post.

I am not going to delve into why this happens, or how to prevent or manage this completely at this point (since I have not figured all of that out just yet), but I did manage to come up with a procedure to open up the last 300 Megabytes of the disk so that I could complete my BitLocker install.

Once you have gone into the Disk Management interface to query available Shrink space, or have used DISKPART "shrink querymax" (see a full explanation of DISKPART usage elsewhere or message me for help), an event will be recorded in the application log regarding the last unmovable file. If you filter the log for an Event Source of Defrag, you will find a recent entry like this:

"A volume shrink analysis was initiated on volume (C:). This event log entry details information about the last unmovable file that could limit the maximum number of reclaimable bytes.

 Diagnostic details:
 - The last unmovable file appears to be: \Windows\CCM\ServiceData\Messaging\EndpointQueues\ClientRegistration\00000001.que::$DATA
 - The last cluster of the file is: 0x45a9698
 - Shrink potential target (LCN address): 0x455982
 - The NTFS file flags are: ----D
 - Shrink phase: <analysis>"

 
As you can see, the location and name of the file is identified. If you browse to this location in explorer and try to cut the file from it's current location and paste it on another physical drive (a "move"), you will get a popup telling you the name of the service preventing it's move, i.e., in this case, "SMS Agent Host". If you stop the service, you can move (cut and paste, not copy) the file to another physical drive and then move it right back again and restart the service. This will almost always use the first open space nearest the beginning of the disk and create more free space at the end of the disk, where the shrink occurs.

Now you can query the available shrink space again using either Disk Management or DISKPART, and if the space is still too small, review the event viewer again and continue to move files and restart services as needed until the available space is achieved. Occasionally, you might find a file locked by some system process that will be trickier to move, as I did. One file I found was locked by Windows Explorer. In this case, I opened Task Manager and killed the Explorer process, and then opened a New Task from the Task Manager menu to run a command prompt and performed the move from there. After the file is moved off and back onto the original drive location, simply open a New Task from the Task Manager menu and type in "explorer" which will revive the graphical Windows interface.

If you are especially unlucky, you might find a file that is truly difficult to move, like


"\System Volume Information\{2d100ba4-2cad-11e4-825d-3417ebae23dc}{3808876b-c176-4e48-b7ae-04046e6cc752}::$DATA"

in which case you will have to work on file permissions to get that moved, if it is even possible to move with Windows running. If not, you might need Safe Mode or might even need to connect the disk to another system instead of booting up that system.

In any event, most files that are declared "unmovable" can be moved with a little fancy footwork. The files are not "unmovable", just locked in their current location by a running service, which would be a much better description in the event (Microsoft tech writers, are you listening?).  :)

So don't believe that annoying little remark in event viewer and make that file obey your will!


"You cahn doo eet!" -- Rob Schneider



- Peter Trast, MCITP EA, MCITP DBA, MCT LinkIn with Peter