Monthly Archive

Categories

Monthly Archives: July 2011

Now this is odd

I have three machines running Windows 7 32 bit

  • an HP laptop running Ultimate
  • an HP netbook running starter edition
  • a Dell duo running Home Premium

I have installed the Kindle for PC reader on each of them.  It installed and worked without any problems - - until today.

I added two books to the Kindle application on the Dell and it suddenly stopped working. Every time I open it I get a Application has stopped working message.

Tried uninstalling & re-installing - still bust

Tried the steps given here - http://blogs.msdn.com/b/saveenr/archive/2010/10/30/stopping-the-amazon-kindle-for-pc-application-from-crashing-on-windows-7.aspx - nope still doesn't work.

How can application go from working fine to unusable? Evidently this problem has been around since autumn last year. Just didn't notice it because it didn't affect me.

I've standardised on Kindle format for ebooks.  This isn't going to be good if the Kindle application stops working on my other laptops

There is no excuse for an application to suddenly decide it isn't going to work.  I have other ebook readers installed and they are working with no problems.

Just a thought

I’ve working with WMI a lot recently and frequently seen things like this

Get-WmiObject -Class Win32_OperatingSystem -ComputerName dc02

Get-WmiObject -Class Win32_ComputerSystem -ComputerName dc02

Get-WmiObject -Class Win32_LogicalDisk -ComputerName dc02

Each of these has to create a connection

is

$sb = {
Get-WmiObject -Class Win32_OperatingSystem
Get-WmiObject -Class Win32_ComputerSystem
Get-WmiObject -Class Win32_LogicalDisk
}

Invoke-Command -ScriptBlock $sb -ComputerName dc02

more efficient

In some cases yes depending on what you want to do with the information. Especially if need to filter data

AD account Expiry date

In many organisations AD accounts for temporary works are set to expiry when their contract ends.  Its also a good practice to put an expiry date on any one who is leaving – that way you know their account won’t available.

Setting the expiry date for all users in an OU is done like this

$date = "01/01/2012 00:00:00"            
            
$ou = [adsi]"LDAP://ou=test,dc=manticore,dc=org"            
            
$search = [System.DirectoryServices.DirectorySearcher]$ou            
$search.Filter = "(&(objectclass=user)(objectcategory=user))"            
$search.SizeLimit = 3000            
$results = $search.FindAll()            
            
foreach ($result in $results){            
            
 $target = $result.GetDirectoryEntry()            
 $target.AccountExpirationDate = $date            
 $target.SetInfo()            
}

 

The date shows the start of a day but the account expires at the end of the previous day.

The attribute is set correctly in ADSIEdit but on my Windows 2008 R2 system AD Users and Computers showed a date 1 day earlier but AD Administrative center shows the correct date!

GPO cmdlets

One thing new I found out today – if you install the Remote Server Administration Tools (RSAT) on Windows 7 you can use the GPO cmdlets (GroupPolicy module) against a Windows 2003 domain controller.

The cmdlets enable all GPO management tasks apart from modifying settings.

Useful

PowerShell remoting–User group meeting

Final reminder for the user group meeting on Tuesday 26 July

Details from:

http://msmvps.com/blogs/richardsiddaway/archive/2011/07/20/july-2011-user-group-reminder.aspx

Just enough

One thing that never seems to stated is that you don’t need to use the full criteria when searching for something. As an example I wanted to know the COM related services running on a system

Get-Service | where {$_.DisplayName -like "*com*"}

supplies

Status   Name               DisplayName
------   ----               -----------
Running  Browser            Computer Browser
Stopped  COMSysApp          COM+ System Application
Running  DcomLaunch         DCOM Server Process Launcher
Running  EventSystem        COM+ Event System
Running  PcaSvc             Program Compatibility Assistant Ser...

which is exactly what I wanted.

Start vague and narrow down rather spending a lot of time trying to refine the criteria up front.  I’ve found its a faster way to get to the results

Moving Windows

In answer to a forum question I started to look at how you could move the PowerShell window from within PowerShell. Its not straight forward as we have to dig into the Win32 APIs

I came up with this code

function move-window {            
param(            
 [int]$newX,            
 [int]$newY            
)             
BEGIN {            
$signature = @'

[DllImport("user32.dll")]
public static extern bool MoveWindow(
    IntPtr hWnd,
    int X,
    int Y,
    int nWidth,
    int nHeight,
    bool bRepaint);

[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
public static extern bool GetWindowRect(
    HandleRef hWnd,
    out RECT lpRect);

public struct RECT
{
    public int Left;        // x position of upper-left corner
    public int Top;         // y position of upper-left corner
    public int Right;       // x position of lower-right corner
    public int Bottom;      // y position of lower-right corner
}

'@            
            
Add-Type -MemberDefinition $signature -Name Wutils -Namespace WindowsUtils             
            
}            
PROCESS{            
 $phandle = [WindowsUtils.Wutils]::GetForegroundWindow()            
            
 $o = New-Object -TypeName System.Object            
 $href = New-Object -TypeName System.RunTime.InteropServices.HandleRef -ArgumentList $o, $phandle            
            
 $rct = New-Object WindowsUtils.Wutils+RECT            
            
 [WindowsUtils.Wutils]::GetWindowRect($href, [ref]$rct)            
             
 $width = $rct.Right - $rct.Left            
 $height = 700            
<#
 $height = $rct.Bottom = $rct.Top
 
 $rct.Right
 $rct.Left
 $rct.Bottom
 $rct.Top
 
 $width
 $height
#>             
 [WindowsUtils.Wutils]::MoveWindow($phandle, $newX, $newY, $width, $height, $true)            
            
}             
}

We start by creating a piece of inline C# that creates a .NET class we can use to call the Win32 API functions. The names of the these functions are self explanatory

The move is accomplished by getting the handle of the foreground window and then creating a handle reference. The current window size is obtained using GetWindowRect – on my Windows 7 machine it doesn’t report the height correctly so I hard code that but calculate the width.

The MoveWindow method can be used to perform the move.  Remember that 0,0 is top left corner of the screen

I’m intrigued as to why the height isn’t reported correctly but haven’t found a good reason

Can I? Should?–copying VBscripts

One of the major errors I see PowerShell newcomers performing is copying script structures and syntax of VBScript into PowerShell. Let me give you an example

This piece of VBScript is borrowed from the Windows 2000 scripting guide

 

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colSettings = objWMIService.ExecQuery _
("SELECT * FROM Win32_OperatingSystem")
For Each objOperatingSystem in colSettings
Wscript.Echo "OS Name: " & objOperatingSystem.Name
Wscript.Echo "Version: " & objOperatingSystem.Version
Wscript.Echo "Service Pack: " & _
objOperatingSystem.ServicePackMajorVersion _
& "." & objOperatingSystem.ServicePackMinorVersion
Wscript.Echo "OS Manufacturer: " & objOperatingSystem.Manufacturer
Wscript.Echo "Windows Directory: " & _
objOperatingSystem.WindowsDirectory
Wscript.Echo "Locale: " & objOperatingSystem.Locale
Wscript.Echo "Available Physical Memory: " & _
objOperatingSystem.FreePhysicalMemory
Wscript.Echo "Total Virtual Memory: " & _
objOperatingSystem.TotalVirtualMemorySize
Wscript.Echo "Available Virtual Memory: " & _
objOperatingSystem.FreeVirtualMemory
Wscript.Echo "OS Name: " & objOperatingSystem.SizeStoredInPagingFiles
Next

It uses the Win32_OperatingSystem class to display information about the computers OS. As you can see the bulk of the script is concerned with formatting. Note the error in the script regarding OS Name

 

What often happens is that this will be translated directly, line by line, into PowerShell – which gives us something like this

$strComputer = "."            
            
$colSettings = Get-WmiObject -Query "SELECT * FROM Win32_OperatingSystem" -ComputerName $strComputer            
foreach ($objOperatingSystem in $colSettings){            
 Write-Host "OS Name: "  $objOperatingSystem.Name            
 Write-Host "Version: "  $objOperatingSystem.Version            
 Write-Host "Service Pack: "  $objOperatingSystem.ServicePackMajorVersion "." $objOperatingSystem.ServicePackMinorVersion            
 Write-Host "OS Manufacturer: "  $objOperatingSystem.Manufacturer            
 Write-Host "Windows Directory: "  $objOperatingSystem.WindowsDirectory            
 Write-Host "Locale: "  $objOperatingSystem.Locale            
 Write-Host "Available Physical Memory: "  $objOperatingSystem.FreePhysicalMemory            
 Write-Host "Total Virtual Memory: "  $objOperatingSystem.TotalVirtualMemorySize            
 Write-Host "Available Virtual Memory: " $objOperatingSystem.FreeVirtualMemory            
}

This is less code but still seems like a lot of work

 

lets put it into PowerShell as if we had written it from scratch

$strComputer = "."            
            
Get-WmiObject -Class Win32_OperatingSystem -ComputerName $strComputer |            
select Name, Version, ServicePackMajorVersion, ServicePackMinorVersion,            
Manufacturer, WindowsDirectory, Locale, FreePhysicalMemory,             
TotalVirtualMemorySize, FreeVirtualMemory

 

Now that is much easier. Quicker to code and easier to understand.

 

By all means use VBscripts as references for using WMI classes (I do) but re-write into PowerShell its much, much easier.

This isn’t a contradiction of my previous post as I advocated leaving legacy VBScript alone until you needed to  modify it

Dell duo tablet

Having bought the Dell Duo a few weeks ago I’ve been giving its tires a good kick. The duo is a combination netbook and tablet. It opens and works like a conventional netbook but the screen flips round and so you can close the lid, have the screen on the outside and use it as a tablet.

As a netbook its great. 1366x768 resolution makes for a very sharp screen. Its fast enough for the applications I want to use – mainly Office & reading PDFs. Keyboard is OK and the touchpad mouse works better than my HP netbook. The lack of an Ethernet port and external video feed are irritants but they can be overcome. Performance is more than enough for what I use it for.

As a tablet it works. Windows 7 isn’t an iPad but it you want  a tablet experience that runs your business applications and is good enough then its OK. I’ve found it especially useful in meetings for scrolling through notes. As the tablet is flat on the table there isn’t the feeling of anything getting in the way that you have when everyone has a laptop open.

All in all its a good buy and a useful addition to my hardware set. I’m tending to use it as a machine for work to carry all my reference material at which it is superb.

Can I? Should I?–examples–legacy scripts

In this post http://msmvps.com/blogs/richardsiddaway/archive/2011/07/17/can-i-should-i.aspx I stated that PowerShell isn’t necessarily the right answer to every problem.

I was left a comment asking if I could expand.  I’ll do that over a series of short posts as I think of examples.

One of the first that comes to mind is legacy scripts.

VBScript never really caught on as a mainstream administration tool. There were a number of reasons for this:

  • non interactive
  • harder to use and debug
  • less information
  • less flexible
  • admins addicted to the GUI
  • less pressure on people i.e. more admins

However, a number of organisations created a significant number of scripts and performed some very clever stuff.

Now, the question for those organisations is this -

“PowerShell has appeared. Do I convert all those scripts, that work really well to PowerShell?”

 

My answer would be no!  Learn PowerShell first . Get really proficient. Develop new stuff in PowerShell and migrate the legacy scripts when they need an over haul (or you get some free timeSurprised smile) that way you get the best of both worlds and run the smallest risk when you come to migrate the legacy scripts.