A quick one-liner to find out a Windows system’s uptime

Based on the info I found here, this one-liner is a quick way of displaying a Windows system’s uptime from the command prompt…

net stats srv | find "since"

Results in the following:

Statistics since 16/05/2013 2:32:48 PM

Oleg left me a comment with a more accurate one:

systeminfo | find "Boot Time"

Just remember that find.exe is case-sensitive unless you use the /i parameter

The “net stats srv” method I originally posted is a little less accurate (by mere seconds) as it’s based on when the Server service started:

image

Note: Edited to include a better, more accurate method

Batch convert images to B&W with PowerShell and ImageMagick

I knocked together this PowerShell script today to batch-convert 600+ staff photo images to B&W.

2012-08-02 14-07-00_000101

You’ll require the following items installed and in your path before this script will work:

  1. ImageMagick. I used the normal version, not one of the alternate ones.
  2. jhead: exif jpeg header manipulation tool. This requires ImageMagick in order to work.

ImageMagick does the actual conversion to B&W. I played with converting to pure grayscale, but it didn’t look good. This method instead strips out all colour information by setting saturation to zero:

convert.exe {sourcefile} -modulate 100,0 {destinationfile}

An issue I came across then is that ImageMagick doesn’t update the embedded JPG thumbnail. This issue almost stumped me, but then I came across this great little tool called jhead. Amongst other things, jhead can regenerate the JPG thumbnail (only if one existed originally):

jhead.exe -rgt {filename}

Tying it all together is PowerShell:

<#
    .SYNOPSIS
    Generate B&W versions of images 
   
       Daniel Streefkerk
    
    THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE 
    RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
    
    Version 10, 02/08/2012
    
    .DESCRIPTION
    
    This script runs though a folder full of images and creates B&W versions of said images
    
    IMPORTANT NOTE: This script requires ImageMagick and jhead. For more information, see my blog
    
    .PARAMETER RootFolder
    The folder within which to process images

    .PARAMETER Recursive
    Also scan subfolders? This is enabled by default
    
    .EXAMPLE
    Process all images in c:temp
    .Generate-BWImages.ps1 -RootFolder c:temp
    
    #>

Param(
  [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false,HelpMessage='The folder that contains the photos')]
  [String]
  #[ValidateScript({Test-Path $_ -PathType 'Container'})] 
  $RootFolder,
  [Parameter(Position=1,Mandatory=$false,ValueFromPipeline=$false,HelpMessage='Recurse through all subfolders?')]
  [bool]
  $Recursive=$true
)

cls

# Change these if necessary
$fileExtensions = "*.jpg"
$fileNameSuffix = "_bw" # the text to be appended to the file name to indicate that it has been modified

$files = $null;
$fileCount = 0

# Check if the root folder is a valid folder. If not, try again.
if ((Test-Path $RootFolder -PathType 'Container') -eq $false) {
    Write-Host "'$RootFolder' doesn't seem to be a valid folder. Please try again" -ForegroundColor Red
    break
}

# Get all image files in the folder
if ($Recursive) {
    $files = gci $RootFolder -Filter $fileExtensions -File -Recurse
} else {
    $files = gci $RootFolder -Filter $fileExtensions -File
}
# If there are no image files found, write out a message and quit
if ($files.Count -lt 1) {
    Write-Host "No image files with extension '$fileExtensions' were found in the folder '$RootFolder'" -ForegroundColor Red
    break
}

# Loop through each of the files and process it
foreach ($image in $files) {
    $newFilename = $image.DirectoryName + "" + $image.BaseName + $fileNameSuffix + $image.Extension
    $imageFullname = $image.FullName

    write-host "Processing image: $imageFullname" -ForegroundColor Green
    & convert.exe $image.FullName -modulate "100,0" $newFilename
    write-host "Updating embedded thumbnail for: $newFilename" -ForegroundColor Green
    & jhead.exe -rgt $newFilename

    $fileCount++
}

Write-Host "$fileCount images processed" -ForegroundColor Yellow

VBScript to disable all users in specified OUs

When staff members leave the organisation, we move their account to a sub-OU named “Leavers” under their office’s OU. This triggers their mailbox to be archived in Enterprise Vault.

I thought it was about time to put together a quick scheduled task to ensure that all these “leavers” were automatically disabled and hidden from the Exchange address lists without IT manually having to do it.

I came across this handy and concise example, and modified it to run through a group of OUs while doing what I needed it to do.

Here’s the code. As always, run at your own risk, and test it before putting it into production:

On Error Resume Next

Dim arrLeaverOrgUnits, objOU
arrLeaverOrgUnits = Array("LDAP://OU=Leavers,OU=Sydney,DC=contoso,DC=com",_
                          "LDAP://OU=Leavers,OU=Melbourne,DC=contoso,DC=com")

For Each strOU in arrLeaverOrgUnits
  Set objOU = GetObject(strOU)
    ' Let's be extra-paranoid here, and make sure we're only working on the leavers OU
    '  in case someone adds the wrong OU into the array above
    If objOU.Name <> "OU=Leavers" Then Exit For
    
    ' Loop through each object in the current OU
    For Each objObject In objOU
      ' If the current object is a user
      If objObject.class="user" then
        'Disable the account
        objObject.AccountDisabled = True
        ' Hide the account from the Exchange address lists
        objObject.Put "msExchHideFromAddressLists", True
        ' Write the information back to the user object in AD
        objObject.SetInfo
        
        'WScript.Echo objObject.Name & " disabled and hidden from Exchange address lists"
      End if
    Next
  Set objOU = Nothing
Next

Native resolution not set after deploying via MDT 2010

If your machines aren’t automatically having their display resolution set to their monitor’s native resolution after deployment via MDT, this may be the cause of the problem.

Although I’d previously deployed Vista and Windows 7 using MDT 2010, I’d never seen this problem. The issue occurred with a captured HP ProBook x86 Windows 7 Professional build.

I had to edit the unattend.xml for the task sequence in question, and delete the Display section from oobeSystem –> x86_Microsoft-Windows-Shell-Setup_neutral. Once this was done, the strange default of 1024 x 768 (where did that come from?) was no longer applied, and Windows Setup detected and set the maximum resolution.

WSIM-res_issue

MDT/WSIM fails to catalog a captured Windows 7 image

Had an issue today where I was trying to catalog a captured Windows 7 WIM image, both through MDT 2010 and through WSIM directly.

Doing so comes up with an error:

Performing operation "generate" on Target "Catalog".
The operation failed to complete.
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentNullException: String reference not set to an instance of a String.
Parameter name: source
   at System.Globalization.CompareInfo.IsPrefix(String source, String prefix, CompareOptions options)
   at ?A0xfe36268f.ConvertToNtPath(String path)
   at Microsoft.ComponentStudio.ComponentPlatformInterface.CbsSessionAdaptor..ctor(String bootDrive, String imageWinDir, String servicingPath)
   at Microsoft.ComponentStudio.ComponentPlatformInterface.OfflineImageImpl.InitializePackages()
   at Microsoft.ComponentStudio.ComponentPlatformInterface.OfflineImageImpl..ctor(OfflineImageInfo imageInfo)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle._InvokeConstructor(Object[] args, SignatureStruct& signature, IntPtr declaringType)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at Microsoft.ComponentStudio.ComponentPlatformInterface.Cpi.PlatformImplementation.CreateOfflineImageInstance(OfflineImageInfo imageInfo)

2012-01-06 11-55-50_DeploymentWorkbench - [Deployment Workbench_Deployment Shares_Sydney MDT Deploym

The captured image I was trying to work with was of a 32-bit machine, and the WAIK tools I have installed on my desktop are the 64-bit ones.

The solution, as I learned here after a bit of searching, is to re-run the catalog operation on an x86 machine.

As you can’t install the 32-bit tools on a 64-bit machine, I installed the 32-bit tools on my laptop, fired up WSIM, opened the WIM image, re-ran the catalog operation, and it succeeded without errors.

You’d think that they could catch the exception and give you a useful message about running the catalog again on a compatible machine, but no…

Server 2008 R2: Online license edition upgrade

I’ve had to google this a few times, so I’ll blog the results here for future reference.

It’s possible to upgrade, for example, a Server 2008 R2 Standard server to Enterprise without rebuilding Windows. This is all covered in detail on the MS TechNet blogs.

The command to do so is:

DISM /online /Set-Edition:<edition ID> /ProductKey:XXXXX-XXXXX-XXXXX-XXXXX-XXXXX

To view what “editions” are available to upgrade to, do this:

DISM /online /Get-TargetEditions

I had issues using a valid VLSC key in this process. A comment by Brendan P of Microsoft explains why this is the case:

MAK keys map to multiple editions, so the underlying infrastructure doesn’t accept them. If you use the generic KMS client key, as Matthew suggests, that will allow you to proceed with the upgrade, and then you can either replace the key with a valid MAK post-upgrade or just use the KMS client key to activate against your internal KMS server.

The full list of KMS client keys can be found here on TechNet: technet.microsoft.com/…/ff793406.aspx

The command I ended up running to upgrade Server 2008 /w SP1 Standard (VL) to Enterprise was:

DISM /online /Set-Edition:ServerEnterprise /ProductKey:489J6-VHDMP-X63PK-3K798-CPX3Y

The successful run looks like this:

Deployment Image Servicing and Management tool
Version: 6.1.7600.16385 Image Version: 6.1.7600.16385 Starting to update components...
Starting to install product key...
Finished installing product key. Removing package Microsoft-Windows-ServerStandardEdition~blah [==========================100.0%==========================] Finished updating components. Starting to apply edition-specific settings...
Restart Windows to complete this operation.
Do you want to restart the computer now (Y/N)?

Determine which DFS target a client is connected to

If you want to figure out which servers your DFS client is connected to, just run the following command from the command prompt:

dfsutil /pktinfo

To quote the inbuilt usage information:

Dfsutil /PktInfo is a special problem diagnosis command that should only be executed on the client.

The PKT Cache keeps information about referrals for previously accessed DFS paths. It also notes DFS targets that are active for each of those paths. By observing the contents of this cache, an expert user may deduct the servers serving DFS paths that are accessed.

Here’s a snippet of the output when run from my PC at work. We have a common DFS share that’s replicated Australia-wide:

Entry: companycommondataShortEntry: companycommondata
Expires in 143 seconds
UseCount: 2 Type:0x81 ( REFERRAL_SVC DFS )   
0:[sydney01CommonData] AccessStatus: 0 ( ACTIVE TARGETSET )   
1:[sydney02CommonData]   
2:[perth01CommonData] ( TARGETSET )   
3:[brisbane01CommonData]   
4:[melbourne01CommonData]   
5:[adelaide01CommonData]

Quick Tip: Set the “FLAGS” value in a captured WIM after capture

Today I had a problem where MDT2010 didn’t apply the correct “FLAGS” value to the OS within the captured WIM when capturing an image via MDT. This shouldn’t happen in theory, but there’s nothing like a gnarly problem when you’re under the pump.

The value was appearing like this:

      <VERSION>
        <MAJOR>6</MAJOR>
        <MINOR>0</MINOR>
        <BUILD>6002</BUILD>
        <SPBUILD>18005</SPBUILD>
        <SPLEVEL>2</SPLEVEL>
      </VERSION>
      <SYSTEMROOT>WINDOWS</SYSTEMROOT>
    </WINDOWS>
    <NAME>CAP-1CDrive</NAME>
    <FLAGS>%OSSKU%</FLAGS>
  </IMAGE>
</WIM>

I found a similar issue and solution in the MDT2010 documentation:

To resolve this issue, add an Edition ID to the image by running the following command (where edition_id is the appropriate SKU ID as defined in the original factory image or in the Windows AIK, wim_file is the name of the WIM file, new_image_name is the new image name, and new_image_description is the new description for the image):

imagex /flags <edition_id> /info <wim_file> 1 <new_image_name> <new_image_description>

In my case, I did the following:

imagex /flags "Business" /info "capture.wim" 1 "Windows Vista Business" "Windows Vista Business x86"

HP Continuous Data Protection application fails to recognise a new RDX cartridge

Just something I came across last week on a SBS 2011 setup; the current version of HP’s CDP software refuses to recognise a newly-inserted RDX cartridge if you’re connected to the server via RDP. This had me puzzled for a while until I connected a monitor, keyboard, and mouse to the server and logged on there. The new cartridge was recognised instantly.

Hopefully they fix this soon, as it’s an issue in headless server setups. I’ve gotten around it for now by using LogMeIn on that server.

HP RDX Cartridge

Server (lanmanserver) service fails to start on Server 2008 after iSCSI config

Just had an issue with three newly-configured Hyper-V Servers (Server 2008 R2 Enterprise) where the Server, or lanmanserver, service was failing to start. Incidentally, all of these (blade) servers are hooked up to a HP LeftHand P4xxx SAN, but are booting from local disk.

Included in the LeftHand setup instructions is a recommendation to make the lanmanserver service dependent on the MSiSCSI service. This is to ensure that any iSCSI volumes are initialised before the Server service starts. To quote the HP documentation:

LeftHand recommends setting sc.exe to create dependencies rather than editing the registry. sc.exe is included with Server 2008 and can be run from an alternate network computer.
From a DOS prompt, type sc config <your_service_name> depend= MSiSCSI.

For example: sc config lanmanserver depend= MSiSCSI.

We had dutifully followed these instructions, but then later noticed that admin shares were inaccessible and that we couldn’t add the three hosts to VMM 2008 R2. During the troubleshooting process, I noticed that the Server service was failing to start with the error “Windows could not start the Server service on Local Computer. Error 2: The system cannot find the file specified.

Cue a wild goose chase for a while due to the uselessness of the error message and absence of any useful information in the error logs. I Then stumbled upon this post on the the TechNet forums in which user “soundstripe” describes the exact same problem (albeit with a different iSCSI SAN). User “m_a_tt” on these forums describes the problem also. I didn’t read that his solution was the same as mine until I had figured it out myself. I also noticed a post on the HP forums where someone was having the same issue, but hadn’t received an answer (in 4 months).

The HP documentation is in effect directing users to remove the original service dependencies for the lanmanserver service, instead of appending the MSiSCSI dependency to the existing list. I’m not sure if that’s because of a difference in the behaviour of the “sc” command in Server 2008 as compared to Server 2003, but I don’t know why I didn’t think of it earlier!

I logged onto another Server 2008 box that had no iSCSI configuration and noticed that the Server service had two dependencies; SamSS, and Srv. My three Hyper-V boxes only had a single dependency for MSiSCSI.

While the HP documentation advises to run the following:

sc config lanmanserver depend= MSiSCSI

The correct command on a stock Windows Server 2008 box should be (Dependencies separated by / (forward slash)):

sc config lanmanserver depend= SamSS/Srv/MSiSCSI

Do the above, and then reboot. This will solve the problem, the Server service will start, and it will still be dependent on the MSiSCSI service.

I hope this saves someone some time!

Edit: I just thought I’d add this footnote after completing HP’s LeftHand SAN training last week; Don’t forget that you may want to set other services as dependencies if their data resides on the iSCSI volumes. For example, I’ll set the Hyper-V service to be dependent on MSiSCSI if the server is a Hyper-V host.