ExitCodes Part 2

So, yesterday I mentioned that I re-wrote the inventory script. Today I decided to re-write the reboot script. The idea behind the script is that once a week we bounce all the lab computers. We do this for various reasons, but since I’m in the mood decided today was the day to tackle that problem.

The last time I talked about this, I got a little off the beaten path hunting down all possible exit codes for the shutdown.exe command. While not wrapped around the axles this time, I did have to figure out how to deal with it.

The nice thing about PowerShell is that when running a command you have access to $LASTEXITCODE. This contains exactly what you think it contains, the number of the return code from the command-line program. Before I get to far ahead I do want to mention that when last I wrote about exit codes I found them on the Symantec site (still works). Today I found an archived newsgroup that had a link to the MSDN site, so I’ll put that here.

Ok, so I decided since I was re-writing this thing I wanted to be a little more accurate in my reporting of errors encountered. Now it was impossible for me to find what error codes are returned from shutdown.exe, most likely because it could be any number. So then I started looking at how I could get what it was using $LASTEXITCODE.

Buried deep in my brain I remembered that there was a net command that would give you a text version of the number.

net helpmsg 53

The network path was not found.

That seemed perfect, What happens if I use $LASTEXITCODE

net helpmsg $LASTEXITCODE

The operation completed successfully.

BRILLIANT! This was perfect, I decided to store the result in a variable and then write it out. The only problem, really more of a hassle, was that it returns a string array.

$result = (& net helpmsg $LASTEXITCODE)



After some poking around I realized that the first row is blank, the second row contains the message and that the remaining rows were empty. So in my case, one line padded top and bottom with empty rows. Then I began to wonder, are all the messages one-liners? So I wrote up a little routine to display all the messages, I’ll give you the final version of it.

$ExitCodes = (0..15818)
foreach ($ExitCode in $ExitCodes)
$ErrorActionPreference = 'SilentlyContinue'
(& net helpmsg $ExitCode)[1]

You might be asking why am I stopping at 15818? If you visited the link I gave you earlier you would have noticed that the codes ran higher than that. In fact the last page of that list is System Error Codes (12000-15999). Well if you scroll to the bottom of that page, you will note it stops at the above listed 15818. Now I don’t know why, but I figured why go any higher right? Well, I did and there isn’t anything there.

This script is pretty straightforward, it loops through each number and passes it to net helpmsg. All I did then was just ask for the second row [1] of that returned object. While I didn’t count all the returned messages, there were a lot, and for my situation, the one line on the second row was plenty for me.


The script can also be downloaded from TechNet.

PowerShell New-AdInventory script

I may have mentioned on here before that we rely quite heavily on Active Directory, and it’s true. It’s at the core of nearly all the services we deliver, the only exception would be the web, and that would really only be the public facing web sites.

I’ve also mentioned before that I’ve been moving over from VbScript to PowerShell, and I think it’s safe to say that I moved over quite a while ago. If you’ve not browsed my scripts you should head over to my code.google.com site to see what I’ve done.

Anyway, today I was working on a problem with a script that runs from a cron and after fixing that one, I realized I was still using my old inventory script to update Active Directory computer objects with some useful information. So I decided it was time that I rolled this script over to PowerShell. Now while I’d like to say the new and improved one is much more wicked awesome, it’s not, it’s just all PowerShell’d up.

The previous script I had created several functions to do things like send data to the event log. A rather generic function to return values from a remote computer via WMI. A nice little function to ping the computer, although looking back at the code I noticed that it’s not actually there, I should fix that.

At any rate the new script seems to go a little faster, and it certainly doesn’t look any shorter but most of that is actually documentation. Although technically since I dot-source in a library it’s significantly larger than the previous script.

This runs every hour and pulls the UserName, MacAddress, IPAddress and SerialNumber from the remote computer via WMI. I then write these values back to the computer object more or less using the same properties. Although description becomes UserName and ipHostNumber becomes IPAddress.

The nice thing is that we can then visually scan a given OU and see who might be logged into a computer. If there is an issue connecting to a computer, that is also written to the description property. That way as you browse your AD you can easily see which computers have problems, typically these are also dead computer accounts.

The code is also available on Technet.

Windows Server 8 Beta Failover Clustering and PowerShell

So the last two posts (one, two) were just some screenshots and comments as I went through and created a failover cluster. To be fair this wasn’t the first go round with the cluster I created one earlier with just one computer so I could see the PowerShell stuff.

I must say, 81 PowerShell commands to handle clustering, not too shabby. The first cluster I created was with the New-Cluster cmdlet.

New-Cluster -Name win8-hv -Node win8-hv1 -NoStorage -Verbose

The progress bar flashed for a bit as it did stuff and then there was a cluster. It didn’t take a long time but it was rather hot I must say.

Here are all the new commands

Get-Command |Where-Object {$_.ModuleName -eq 'FailoverClusters'} | Format-Table -Property Capability, Name -AutoSize

Capability Name
---------- ----
Cmdlet Add-VMToCluster
Cmdlet Remove-VMFromCluster
Cmdlet Add-ClusterCheckpoint
Cmdlet Add-ClusterDisk
Cmdlet Add-ClusterFileServerRole
Cmdlet Add-ClusterGenericApplicationRole
Cmdlet Add-ClusterGenericScriptRole
Cmdlet Add-ClusterGenericServiceRole
Cmdlet Add-ClusterGroup
Cmdlet Add-ClusteriSCSITargetServerRole
Cmdlet Add-ClusterNode
Cmdlet Add-ClusterPrintServerRole
Cmdlet Add-ClusterResource
Cmdlet Add-ClusterResourceDependency
Cmdlet Add-ClusterResourceType
Cmdlet Add-ClusterScaleOutFileServerRole
Cmdlet Add-ClusterServerRole
Cmdlet Add-ClusterSharedVolume
Cmdlet Add-ClusterVirtualMachineRole
Cmdlet Add-ClusterVMMonitoredItem
Cmdlet Block-ClusterAccess
Cmdlet Clear-ClusterDiskReservation
Cmdlet Clear-ClusterNode
Cmdlet Get-Cluster
Cmdlet Get-ClusterAccess
Cmdlet Get-ClusterAvailableDisk
Cmdlet Get-ClusterCheckpoint
Cmdlet Get-ClusterGroup
Cmdlet Get-ClusterLog
Cmdlet Get-ClusterNetwork
Cmdlet Get-ClusterNetworkInterface
Cmdlet Get-ClusterNode
Cmdlet Get-ClusterOwnerNode
Cmdlet Get-ClusterParameter
Cmdlet Get-ClusterQuorum
Cmdlet Get-ClusterResource
Cmdlet Get-ClusterResourceDependency
Cmdlet Get-ClusterResourceDependencyReport
Cmdlet Get-ClusterResourceType
Cmdlet Get-ClusterSharedVolume
Cmdlet Get-ClusterVMMonitoredItem
Cmdlet Grant-ClusterAccess
Cmdlet Move-ClusterGroup
Cmdlet Move-ClusterResource
Cmdlet Move-ClusterSharedVolume
Cmdlet Move-ClusterVirtualMachineRole
Cmdlet New-Cluster
Cmdlet Remove-Cluster
Cmdlet Remove-ClusterAccess
Cmdlet Remove-ClusterCheckpoint
Cmdlet Remove-ClusterGroup
Cmdlet Remove-ClusterNode
Cmdlet Remove-ClusterResource
Cmdlet Remove-ClusterResourceDependency
Cmdlet Remove-ClusterResourceType
Cmdlet Remove-ClusterSharedVolume
Cmdlet Remove-ClusterVMMonitoredItem
Cmdlet Repair-ClusterSharedVolume
Cmdlet Reset-ClusterVMMonitoredState
Cmdlet Resume-ClusterNode
Cmdlet Resume-ClusterResource
Cmdlet Set-ClusterLog
Cmdlet Set-ClusterOwnerNode
Cmdlet Set-ClusterParameter
Cmdlet Set-ClusterQuorum
Cmdlet Set-ClusterResourceDependency
Cmdlet Start-Cluster
Cmdlet Start-ClusterGroup
Cmdlet Start-ClusterNode
Cmdlet Start-ClusterResource
Cmdlet Stop-Cluster
Cmdlet Stop-ClusterGroup
Cmdlet Stop-ClusterNode
Cmdlet Stop-ClusterResource
Cmdlet Suspend-ClusterNode
Cmdlet Suspend-ClusterResource
Cmdlet Test-Cluster
Cmdlet Test-ClusterResourceFailure
Cmdlet Update-ClusterIPResource
Cmdlet Update-ClusterNetworkNameResource
Cmdlet Update-ClusterVirtualMachineConfiguration

So let’s play a little.

jeffpatton.admin@WIN8-HV1 | 12:56:01 | 03-20-2012 | C:Usersjeffpatton.admin #

Name OwnerNode State
---- --------- -----
Available Storage win8-hv2 Offline
broker win8-hv2 Online
Cluster Group win8-hv2 Online

jeffpatton.admin@WIN8-HV1 | 12:56:04 | 03-20-2012 | C:Usersjeffpatton.admin #
Remove-ClusterGroup -Name broker -RemoveResources

Are you sure that you want to remove the clustered role 'broker'? The resources will be taken offline.
[Y] Yes [N] No [S] Suspend [?] Help (default is "Y"): y
jeffpatton.admin@WIN8-HV1 | 12:56:20 | 03-20-2012 | C:Usersjeffpatton.admin #
Remove-Cluster -Name win8-hv

Are you sure you want to completely remove the cluster win8-hv?
[Y] Yes [N] No [S] Suspend [?] Help (default is "Y"): y
jeffpatton.admin@WIN8-HV1 | 12:56:45 | 03-20-2012 | C:Usersjeffpatton.admin #
Get-Cluster : The cluster service is not running. Make sure that the service is running on all nodes in the cluster.
There are no more endpoints available from the endpoint mapper
At line:1 char:1
+ Get-Cluster
+ ~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-Cluster], ClusterCmdletException
+ FullyQualifiedErrorId : Get-Cluster,Microsoft.FailoverClusters.PowerShell.GetClusterCommand

So I just dumped the cluster, I think I’ll create the cluster again with a single node, and then add a node after the fact, since there is a cmdlet for that.

New-Cluster -Name win8-cluster -Node win8-hv1 -NoStorage -Verbose


Let’s confirm that it’s there.

Get-Cluster |Format-List -Property *

Domain : soecs.ku.edu
Name : win8-cluster
AddEvictDelay : 60
BackupInProgress : 0
ClusSvcHangTimeout : 60
ClusSvcRegroupOpeningTimeout : 5
ClusSvcRegroupPruningTimeout : 5
ClusSvcRegroupStageTimeout : 5
ClusSvcRegroupTickInMilliseconds : 300
ClusterGroupWaitDelay : 120
MinimumNeverPreemptPriority : 3000
MinimumPreemptorPriority : 1
ClusterEnforcedAntiAffinity : 0
ClusterLogLevel : 3
ClusterLogSize : 300
CrossSubnetDelay : 1000
CrossSubnetThreshold : 5
DefaultNetworkRole : 2
Description :
FixQuorum : 0
HangRecoveryAction : 3
IgnorePersistentStateOnStartup : 0
LogResourceControls : 0
PlumbAllCrossSubnetRoutes : 0
PreventQuorum : 0
QuorumArbitrationTimeMax : 20
RequestReplyTimeout : 60
RootMemoryReserved : 4294967295
RouteHistoryLength : 0
SameSubnetDelay : 1000
SameSubnetThreshold : 5
SecurityLevel : 1
SharedVolumeCompatibleFilters : {}
SharedVolumeIncompatibleFilters : {}
SharedVolumesRoot : C:ClusterStorage
SharedVolumeSecurityDescriptor : {1, 0, 4, 128...}
ShutdownTimeoutInMinutes : 20
UseNetftForSharedVolumes : 1
UseClientAccessNetworksForSharedVolumes : 0
SharedVolumeBlockCacheSizeInMB : 0
WitnessDatabaseWriteTimeout : 300
WitnessRestartInterval : 15
EnableSharedVolumes : Enabled
DynamicQuorum : 1
Id : d4e05676-cf3d-4814-a828-f32e106bb1c0

Let’s see some information about the node.

Get-ClusterNode |Format-List *

Cluster : win8-cluster
State : Up
Id : 1
Name : win8-hv1
NodeName : win8-hv1
NodeHighestVersion : 467002
NodeLowestVersion : 467002
MajorVersion : 6
MinorVersion : 2
BuildNumber : 8250
CSDVersion :
NodeInstanceID : 00000000-0000-0000-0000-000000000001
Description :
DrainStatus : NotInitiated
DrainTarget : 4294967295
DynamicWeight : 1
NodeWeight : 1

Okay, let’s add a node now. I chopped off the crazy long report filename.

Add-ClusterNode -Name win8-hv2 -Cluster win8-cluster -NoStorage -Verbose
Report file location: C:WindowsclusterReportsAdd Node Wizard



Name ID State
---- -- -----
win8-hv1 1 Up
win8-hv2 2 Up

How many cluster do I have? Seems like a lot, but the Windows 8, and dev-cluster aren’t actually there anymore.

Get-Cluster -Domain soecs.ku.edu


Let’s add server role, this is basically a cluster end-point

Add-ClusterServerRole -Name Win8ServerRole -Cluster win8-cluster -Verbose

Name OwnerNode State
---- --------- -----
Win8ServerRole win8-hv1 Online

How about some details on that role. I cut out the Type property to keep it readable.

Get-ClusterResource -Name win8serverrole |Get-ClusterParameter

Object Name Value
------ ---- -----
win8serverrole Name WIN8SERVERROLE
win8serverrole DnsName Win8ServerRole
win8serverrole Aliases
win8serverrole RemapPipeNames 0
win8serverrole HostRecordTTL 1200
win8serverrole RegisterAllProvidersIP 0
win8serverrole PublishPTRRecords 0
win8serverrole ResourceData {1, 0, 0, 0...}
win8serverrole StatusNetBIOS 0
win8serverrole StatusDNS 0
win8serverrole StatusKerberos 0
win8serverrole CreatingDC \DC1.soecs.ku.edu
win8serverrole LastDNSUpdateTime 3/20/2012 6:17:30 PM
win8serverrole ObjectGUID e3fbfe6ba596a447a09fd4e117...

Windows Server 8 Beta Failover Clustering Part 2

There were so many images that I decided to split this up over several posts. In Part 1, I got the Failover Cluster feature installed on my first server, and now I’m going to work through the Failover Cluster Management tool.


So, the interface doesn’t look any different. I was hoping for something that was part of the Dashboard.


So here is the wizard, it’s really almost identical to Windows 2008 R2, but what the heck.


I’ve selected both servers to be nodes in my new cluster.


Oh wait! I forgot to install the Failover Cluster feature on win8-hv2!


No worries, I got it covered, I can add that feature remotely from the dashboard. That option has to be one of the coolest one’s I’ve seen.


Needless to say the feature installed successfully and I’m able to proceed now.


None of the hardware I’m using is technically support by Microsoft but it’s Beta software so who cares right? Let’s see what the report says though.


Welcome to the Wizards, is it just me or are there more of them?


Lets run everything, I know it will have issues, as both machines are different and don’t have the same sets of software available.


Here we go…


That looks good!


OUCH! Well, win8-hv2 doesn’t actually have Hyper-V installed and since that was in the test, that’s where it failed.


The report confirms this. But again, thanks to being able to remotely install Roles and Features, I installed Hyper-V on the other server and re-ran the tests.


Much happier! For the record, there are several warnings.

  • Hyper-V : The processors are different between the two machines.
  • Network : I don’t have redundant network cards
  • Storage : I don’t have any storage available suitable for some types of clustering, which could be an issue for Hyper-V (Clustered Shared Volumes)
  • System Configuration : To be honest, I didn’t actually look at this, I was aware of the others so I assume there is something minor missing or different between the two nodes.


Here we go, this is good enough to move on to create the end-point for the cluster. This is one of the ways you’ll be able to manage it.


Here it is saying it’s going to steal some IP’s from my range


My cluster is forming!


I was successful! But there were warnings, basically it’s telling me I don’t have any sort of network storage to use for this cluster, of which we were already aware.


Huzzah! The one warning was from the cluster I built earlier with just the one node. Perhaps should have nuked the cluster log, oh well.

Windows Server 8 Beta Failover Clustering Part 1

I read a very nice article over on TechNet about some of the new features of Failover Clustering in Windows 8, so I decided to give it a spin. It’s not too bad, I’m really enjoying the new Server Manager interface, it’s pretty awesome.

Here are the screenshots of the setup process.


Here is the dashboard, this particular computer was upgraded to Windows 8 Server from Windows 2008 R2, so there were already a few roles installed.


Similar interface for adding the Failover Clustering Role


I’ve not tried the Remote Desktop VDI stuff yet, I’m thinking I may grab a couple of more machines and start over with fresh installs.


Here you can install roles onto one of the servers in your pool. I added win8-hv2.soecs.ku.edu to the pool so I could manage both servers from one interface, cool huh?

There is also the option to install the role to VHD, I will have to try that later!


Here you can see the installed roles from Windows 2008 R2


There’s the feature I’m after, Failover Clustering. Note the additional tools, there are 81 PowerShell cmdlets available for managing Failover Clustering. I’m going to post those up after this.


Here is everything that will be installed, I checked the box to Restart the destination if necessary, but for this feature it’s not necessary. But as I was messing around with various other components earlier this week, that’s a nice option.


The installation is starting, you can see the notification flag now has a 1 inside it’s little box. You can close this window and the install will progress.


Clicking on the notification flag, you can see all tasks that are currently running.


Here is what you see when you click details. By the time I got to this screen the installation was done.


I can manage the Cluster from the Dashboard | Tools menu


Since it’s installed on win8-hv1 I can right click on that server in the Server Pool and select Failover Cluster Manager from there.


Perhaps this is silly to point out, but the Failover Clustering feature was not installed on win8-hv2 and so you don’t see the option to manage it from there.

RDP over SSH

Before I start, while this will allow you to access your servers over a secure tunnel, this does not mean you should forego patching your systems.

Don’t be that kind of admin, install the patches, install the critical updates, do us all a favor and make your gear as secure as you can.

I know this is not a new topic, but it’s rather new to me. The university has decided to block RDP at the border after the latest RDP exploit. For the record the university does provide a VPN which will work for most folks, but I don’t often have a machine that I can do that from. The nice thing about putty is it’s a simple download and you don’t have to install it, just download and go.

I’m not going to tell you how to setup an ssh server, mostly because it’s pretty straightforward.

Here we go

  1. Download and start putty
  2. Type in your connection information admin@server.company.com
  3. Open Connections, SSH, Tunnels
  4. Set the source port to be 3391
  5. Set the destination port to be rdp-server.company.com:3389
  6. Click add, and then open the connection
  7. Start the RDP client
  8. Make a connection to localhost:3391
  9. You may be prompted for all that new connection stuff and then finally credentials

You should now have a connection established to your remote desktop server that is being tunneled through your SSH connection.