Thursday 26 June 2014

Powershell: OS Detection

What OS am I executing on? What bitness? Some Handy Functions to Use


Sometimes, it's important to know what OS you are running on, and/or how many bits that OS has. Here are some useful functions which can be reused in other Powershell scripts (a future post may include putting such things into a Powershell Module). Please note that this hasn't been 100% tested on all of the OSes identified, but should work*.

The other two functions are about detecting bitness - Get-OSBitness() will tell you if you are on a 64-bit or 32-bit OS, and Get-CurrentProcessBitness() will tell you what the current Powershell execution-engine is (ie you can detect if you are running on the 32-bit powershell.exe on a 64-bit OS). I can't really image G-CPB() being used much, but here it is anyway.

* Please also note that the Win8.1/2012R2 detection is known to be sometimes incorrect, and these OSes can instead show up as Win8/2012 (respectively); this is because Microsoft broke the detection mechanism in these OSes, and each application now must use a manifest.xml file to flag itself as a Win8.1/2012R2 app (as ooposed to a legacy <= Win8) - I'm pretty sure Powershell.exe is properly manifested and should detect as Win8.1, but the default Powershell ISE is not (at this current time) and will show Win8.



Function Get-OSVersion() {
    # Version numbers as per http://www.gaijin.at/en/lstwinver.php
    $osVersion = "Version not listed"
    $os = (Get-WmiObject -class Win32_OperatingSystem)
    Switch (($os.Version).Substring(0,3)) {
        "5.1" { $osVersion = "XP" }
        "5.2" { $osVersion = "2003" }
        "6.0" { If ($os.ProductType -eq 1) { $osVersion = "Vista" } Else { $osVersion = "2008" } }
        "6.1" { If ($os.ProductType -eq 1) { $osVersion = "7" } Else { $osVersion = "2008R2" } }
        "6.2" { If ($os.ProductType -eq 1) { $osVersion = "8" } Else { $osVersion = "2012" } }
        # 8.1/2012R2 version detection can be broken, and show up as "6.2", as per http://www.sapien.com/blog/2014/04/02/microsoft-windows-8-1-breaks-version-api/
        "6.3" { If ($os.ProductType -eq 1) { $osVersion = "8.1" } Else { $osVersion = "2012R2" } }
    }
    return $osVersion
}


Function Get-CurrentProcessBitness() {
    # This function finds the bitness of the powershell.exe process itself (ie can detect 32-bit powershell.exe on a win64)
    $thisProcessBitness = 0
    switch ([IntPtr]::Size) {
        "4" { $thisProcessBitness = 32 }
        "8" { $thisProcessBitness = 64 }
    }
    return $thisProcessBitness
}

Function Get-OSBitness() {
    # This function finds the bitness of the OS itself (ie will detect 64-bit even if you're somehow using 32-bit powershell.exe)
    $OSBitness = 0
    switch ((Get-WmiObject Win32_OperatingSystem).OSArchitecture) {
        "32-bit" { $OSBitness = 32 }
        "64-bit" { $OSBitness = 64 }
    }
    return $OSBitness
}


Tuesday 24 June 2014

Windows Update Client - Useful Commands


Windows Update is a key tool in diagnosing many Windows-related problems. It's handy to know a few shortcuts to assist in diagnosis.

GUI

There is a basic GUI built into Windows (since Vista). This can be instantly accessed by typing the command  "wuapp", which works if you type this word into a Cmd window, into the Win7 Start Menu and also into the Windows 8/8.1/2012 Metro interface Start Menu.

This GUI will tell you if Updates are working, and show you a history of installed updates.

Command Line Client

The following commands will force the local client to do things:
REM Check for new updates:
wuauclt /detectnow
REM Install any new pending updates (warning, this may reboot your machine)
wuauclt /updatenow
REM NB: above command doesn't seem to work properly any more on Server 2012

REM Forec a Report into WSUS (may be useful if client says it is updated in WUapp, but WSUS says it is still missing patches):
wuauclt /reportnow
REM Force a machine to reregister with its WSUS server (not usually that useful):
wuauclt /resetauthorization /detectnow

Restart the Windows Service

Quite a few problems are resovled by restarting the WU service on a client. The easiest way to restart the service is via the command line:
net stop wuauserv
net start wuauserv

Key Registry Locations

Check the following keys for information:
General Settings will show you a few items, including NextDetectionTime (the Policy key is usually more useful though):
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate

 (Group) Policy Settings include which (if any) local WSUS server you are using, and what the scheduled settings are:
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate

Log File

Log file is located here: %windir%\WindowsUpdate.Log
I won't go through it much, but the log file often contains a lot of errors which aren't neccessarily relevant. The important bits are:
  • Can the WU Service on the machine access the WSUS server and/or internet to check-for and download patches?
  • Is there a problematic update which is failing to apply?
  • Are there other obvious errors?

Web Proxy Issues

Often, downloading issues are caused by a web proxy. Check and/or Reset the Machine's proxy settings (which are different to the logged in users' settings) with the following script (written in "Batch" to work across the whole gamut of OSes). Please note I haven't needed to try this on Server 2012/Win8 yet, so it may have changed.

@setlocal
@echo off

REM This Script resets the machine-level proxy config to autodetect & autoscript.

REM We need bitsadmin to do this - which is built into =>2008/Vista+, but not =<XP/2003
SET bitsadmin=bitsadmin
if not exist %windir%\system32\bitsadmin.exe SET bitsadmin="%~dp02003_bitsadmin_x86.exe"
REM Please note the above line probably doesn't cover 64-bit 2003...

Echo **
Echo ** Output current proxies to the screen (in case someone is watching this)
Echo **
%bitsadmin% /util /getieproxy networkservice 2>/nul
%bitsadmin% /util /getieproxy localservice 2>/nul
%bitsadmin% /util /getieproxy localsystem 2>/nul


Echo **
Echo ** Reset the proxy config on the machine to autodetect/Autoscript
Echo **
proxycfg -d 2>/nul
netsh winhttp reset proxy 2>/nul

%bitsadmin% /util /setieproxy networkservice NO_PROXY 2>/nul
%bitsadmin% /util /setieproxy localservice NO_PROXY 2>/nul
%bitsadmin% /util /setieproxy localsystem NO_PROXY 2>/nul

%bitsadmin% /util /setieproxy networkservice AUTODETECT 2>/nul
%bitsadmin% /util /setieproxy localservice AUTODETECT 2>/nul
%bitsadmin% /util /setieproxy localsystem AUTODETECT 2>/nul

%bitsadmin% /util /setieproxy networkservice AUTOSCRIPT http://wpad/wpad.dat 2>/nul
%bitsadmin% /util /setieproxy localservice AUTOSCRIPT http://wpad/wpad.dat 2>/nul
%bitsadmin% /util /setieproxy localsystem AUTOSCRIPT http://wpad/wpad.dat 2>/nul



Last Resort: Reset the WU Service

The following commands perform a full reset of the WU client-side stuff. Try not to do this unless you know that your machine is quite busted.
This works on all OSes 2012R2 and below, and mostly works on XP/2003, but you need a copy of bistadmin.exe from the 2003R2 Tools (or Resource Kit, I forget).  This is written in "Batch" to work across the whole gamut of OSes.

echo ********************************************************
echo ** Now resetting Windows Update Services on this machine

echo ********************************************************

REM Set the date format for later use. Please note this is __highly__ Locale Dependent, for non-Australian machines "old" is used instead.
FOR %%A IN (%Date%) DO (
    FOR /F "tokens=1-3 delims=/-" %%B in ("%%~A") DO (
        SET ISODATE=%%D%%B%%C
    )
)
SET ISODATE=%ISODATE:~0,8%
echo %ISODATE% | findstr /r "^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]" >NUL 2>&1
IF ERRORLEVEL 1 SET ISODATE=Old

echo ********************************************************echo ** We start by stopping the services
echo ********************************************************
sc config wuauserv start= disabled
net stop wuauserv

echo.
echo ********************************************************echo ** Now we reset all BITS downloads and stop BITS serviceecho ********************************************************SET bitsadmin="bitsadmin"
if not exist "%windir%\system32\bitsadmin.exe" SET bitsadmin="%~dp02003_bitsadmin_x86.exe"
%Bitsadmin% /RESET /ALLUSERS
%Bitsadmin% /RESET
sc config bits start= disabled
net stop bits
net stop wuauserv

echo.
echo *******************************************************
echo ** Next, we delete the detection times
echo *******************************************************
reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v AUState /f >nul 2>&1
reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v NextDetectionTime /f >nul 2>&1
reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v ScheduledInstallDate /f >nul 2>&1
reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v DownloadExpirationTime /f >nul 2>&1

echo.
echo *******************************************************
echo ** Now we archive the log
echo *******************************************************
move "%windir%\WindowsUpdate.log" "%windir%\WindowsUpdate.log.%ISODATE%"

echo.
echo *******************************************************
echo ** Now we archive the internal datastore
echo *******************************************************
move "%windir%\SoftwareDistribution" "%windir%\SoftwareDistribution.%ISODATE%"
rmdir /q /s "%ALLUSERSPROFILE%\Application Data\Microsoft\Network\Downloader"

echo.
echo *******************************************************
echo ** Now we re-register all the DLLs (just to be safe)
echo *******************************************************
regsvr32 /s wuapi.dll
regsvr32 /s wuaueng.dll
regsvr32 /s wuaueng1.dll
regsvr32 /s wuauserv.dll
regsvr32 /s wucltui.dll
regsvr32 /s wups.dll
regsvr32 /s wups2.dll
regsvr32 /s wuweb.dll
regsvr32 /s qmgrprxy.dll
regsvr32 /s qmgr.dll
regsvr32 /s atl.dll
regsvr32 /s jscript.dll
regsvr32 /s msxml3.dll

echo.
echo *******************************************************
echo ** Now we restart the services, and see how we go
echo *******************************************************
REM We set it twice, first to auto then delayed; sometimes the sc call fails for -delayed, and we don't want to leave it in a Disabled state
sc config wuauserv start= auto
sc config bits start= auto
sc config wuauserv start= delayed-auto
sc config bits start= delayed-auto
net start bits
net start wuauserv

echo.
echo *******************************************************
echo ** Now we wait for 30 seconds, and then we trigger a client detection
echo *******************************************************
ping -n 30 127.0.0.1 >nul
wuauclt /resetauthorization /detectnow

echo.
echo *******************************************************
echo ** All done (fingers crossed!)
echo *******************************************************





Monday 16 June 2014

Android SMS on 4.4 KitKat - Goodbye Hangouts, Hello 8sms

I tried, I really tried, to like Hangouts. I even tried to simply live with it. But, enough is enough, and it has now been replaced. Did I fail? No, this time, it's not me - so Goodbye Google Hangouts, Hello 8sms.


For those not in posession of a new-ish Android device, Google has replaced the standard SMS app in the current latest version of Android (v4.4, KitKat) with their own "Hangouts" app, instead of a dedicated SMS app. According to Google, this is supposedly superior (apparently it integrates with Gmail in some way, not that I noticed). However, Hangouts is the first SMS app in many years that left me confused from the very start; for instance, it took me much longer to work out how to create a new SMS in Hangouts than any other phone prior (and I've used Android since v2.1, and many, many other phones from many other manufacturers).

Usually, I assume user-error/ignorance with these things - it's up to me to adjust to a new way,  and the new way is better... and most often this truly is the case. But for Hangouts, it's been three months now, and I can say I know it's not me.

I'm going to skip any more of why I (and every single other person I have asked) think Hangouts is lacking in basic usability, and will jump straight into how to fix the problem: install 8sms from the Play Store (bonus marketing links here: https://play.google.com/store/apps/details?id=com.thinkleft.eightyeightsms.mms and http://8s.ms/.) 8sms is essentially the same stock SMS app which has been used as the default SMS app for all Androids v4.3 and prior; the developer has simply forked the AOSP code, added a few new bits including KitKat compatability, and posted it with the moniker "8sms".

Upon installation, 8sms imported all of my existing SMSes from Hangouts, and (with a few security prompts) switched itself to be my default send/recv SMS app. So simple - and now SMS on my phone works like SMS always has (better, actually). It's good when things Just Work Properly.

Update, Oct 2014:  As lovely as 8sms is, the developer has recently added advertisements into the base app, which is a "feature" not present when I switched apps and made my original blog post. This may or may present a problem for you: Apparently you can make a donation & remove the ads, but I haven't updated the app yet, so I can't verify any of this info. I'll leave it up to your own sound judgement as to whether paying for an app is worthwhile.