Virtualbox on Windows 8 Host – Poweshell Code to Fix Resume from Standby Network Issue

I’ve always been a big fan of Virtualbox.  It has some of the best tools for converting images between different hypervisors and is a leader in its support for different configurations.  Virtualbox is a great option for testing out new or different OS’s and configurations.  I don’t have to run a crippled hypervisor on my system or run some trialware just to try the latest bits.

Microsoft made a lot of changes to the Windows 8 network stack.  One of the more obvious is the speed in which network connections resume from sleep or standby.  Unfortunately, since running Virtualbox on the Dev Preview and on the Final Release, a bug in the Virtualbox Bridged Adapter breaks network connectivity.  Below are a few ways to work around this issue.  You can find more at the bugtraq I submitted to Oracle here: https://www.virtualbox.org/ticket/10317.

Option 1: Disable Virtualbox Bridged Adapter

For me, NAT adapters had too many draw backs to my testing and use.  But, this is how I have been running until I got off my laurels and automated the disable/enable routine outlined in option 3.

  1. In Windows, go to: Control Panel\Network and Internet\Network Connections
  2. Right click the affected/in-use network adapter and select properties
  3. In the items list, uncheck the VirtualBox Bridged Network Adapter
  4. Hit OK and you should be all set

Option 2: Disable/Re-Enable Adapters After Resuming

Doing this manually is extremely laborious and usually ends up with you giving up on bridged adapters.  Either select option 1 or 3.  But, it may save you if you just installed Virtualbox and haven’t had the chance to implement option 1 or 3.

  1. In Windows, go to: Control Panel\Network and Internet\Network Connections
  2. Right click the affected/in-use network adapter and select disable
  3. Right click the affected/in-use network adapter and select enable

Option 3: Automate Option 2

The following steps will create a task that will automatically disable and reenable you network adapters upon resume.  This will slow down reconnects but will allow the use of the VirtualBox Bridged Network Adapter.

  1. Create and save a script with the following command:
    1. gwmi Win32_NetworkAdapter -EnableAllPrivileges | ? { $_.PhysicalAdapter -and $_.NetEnabled } | % { $_.Disable(); $_.Enable() }
  2. Open the Event Log and go the the System Event Log
  3. Look/Search/Filter for Event ID 1, Source Power-Troubleshooter
  4. Right click on Event and select “Attach Task to this Event”
  5. In the Action section, under Program/script, enter: powershell.exe
  6. In the Arguments section, enter: c:\scripts\virtualbox-hack.ps1
    1. Make sure the path and name matches what you named your script in step 1
  7. On the finish screen, check the box “Open the Properties diaglog…” and press OK
  8. On the General tab of the task properties, select:
    1. “Run whether user is logged in or not”
    2. “Run with highest privilges”
  9. Select OK. It should prompt you for credentials. Enter the credentials and you are done.

The New Outlook.com and the Microsoft Account PaymentHub

Outlook.com Logo

While checking my RSS feeds for the night, I ran across this article describing the new Outlook.com.  As an avid user of “Live for Domains“, I was interested to see where Microsoft was going after announcing the renaming of the “Windows Live” moniker back in May.

Outlook.com

It turns out, the UI is refreshing and seems to be a new front-end for what was Hotmail and Live Mail.  It is a refreshing, minimalistic UI with a lot of white space.   Users of the preview releases of Windows 8 will notice many UI and usability similarities.  I was expecting to get a ‘preview like’ experience but that has not been the case.  I have several domains I use and have linked together.  The authentication worked like a charm and I was able to jump around my three different accounts in Outlook.com without it reverting to the old Hotmail interface (send-as working as well).

 

Outlook.com - Service Ribbon

Then I went to check out the Contacts/People interface and the Calendar.  The Calendar never loaded in Chrome so I had to revert to IE.  The Contacts/People interface had the opposite problem; it loads in Chrome just fine but not IE 10.  The Contacts/People interface matches the new UI but the Calendar has yet to be upgraded.  I

‘m sure MS will sort out these issues fairly quickly as they have already surpassed 1 million usersin the new UI.Try it now.  All it takes is a visit to Outlook.com.

Microsoft Account and PaymentHub

This is just speculation but I can see this really fitting into subscription services for Microsoft Office, Xbox games, additional e-mail and SkyDrive storage, advanced features in future releases of WebApps and more.Some people have been reporting running in the new “Microsoft Account” when logging in but this hasn’t been my experience.  However, after the switch, I went into the Outlook.com options/settings and saw a new billing tab.  I also noticed I was now at https://account.live.com/.  The link redirected to https://commerce.microsoft.com/PaymentHub/.  It appears this will handle subscriptions down the road and also function on a point system similar to Xbox Live and Bing Rewards.  It also identifies my account as a ‘US – Personal Account’ leading me to believe they may be using the same billing system used with the preview release of Office365.

Screenshots

What’s Next

With the release of Windows 8, Server 2012, Exchange 2013, Surface Tablets, Office365 Next, Sharepoint 2013, Office 2013, advancements w/ Azure IaaS and more, it is an exciting time for Microsoft.

 

SBS 2011: DistrubutedCOM Error 10016

Pay no attention to the DCOM behind the curtain!

On your SBS 2011 server, do you find a lot of DCOM errors in your System Event Log? These are relatively common on SBS boxes. Microsoft’s guidance is that these can be safely ignored. However, when an error is reported, I expect it to be something that should be investigated. If it can be ignored, it shouldn’t be reporting it as an error. Fortunately, there is a fix for these.

Each event listed below is has the same alert level of “Error” and the same Event ID “10016″. The fixes are all mostly the same with a few differences. Below, I outline each specific error I saw on a specific SBS 2011 box and highlight the differences in fixing each different error. The key differences are the different user account account missing the rights and the different CLSID and APPID. If you find other DCOM errors that this fix works on, let me know and I’ll add it to the list.
Event Information:

Log Name: System
Source: Microsoft-Windows-DistributedCOM
Event ID: 10016
Level: Error
User: NETWORK SERVICE

CLSID 90DCAB7F-347C-4BFC-B543-540326305FBE

Description: The machine-default permission settings do not grant Local Activation permission for the COM Server application with CLSID {90DCAB7F-347C-4BFC-B543-540326305FBE} and APPID {FA3FC5CF-0304-4CAC-99F0-032AC2B15D1E} to the user NT AUTHORITY\NETWORK SERVICE SID (S-1-5-20) from address LocalHost (Using LRPC). This security permission can be modified using the Component Services administrative tool.

To Fix This Error:

  1. Open regedit and select “HKEY_CLASSES_ROOT”
  2. Go the Edit menu and select “Find…” (Ctrl+F)
  3. Enter the APPID in the search dialog and press find: FA3FC5CF-0304-4CAC-99F0-032AC2B15D1E
  4. Right click on the key and select permissions
  5. Click the Advanced Button and select the Owner tab
  6. Take ownership of the object, check the “Replace Owner on Subcontainers” and Objects check-box, and press OK
  7. Grant “Administrators” Full Control and press OK
  8. Note the default value of the found registry key. Should be: “File Server Resource Management Service”. Close the registry editor.
  9. Launch the Component Services MMC: Start → Run → comexp.msc (make sure to run as administrator if using UAC)
  10. Expand: Component Services → Computers → My Computer → DCOM Config
  11. Find “File Server Resource Management Service”, right click it and select properties
  12. Select the Security Tab and press the “Edit…” button in the “Launch and Activation Permissions” group box
  13. Select the “Network Service” account, check the “Local Activation” right and press OK.
  14. Click OK and close the Windows. The DCOM error should be resolved.

CLSID 61738644-F196-11D0-9953-00C04FD919C1


Description: The application-specific permission settings do not grant Local Activation permission for the COM Server application with CLSID {61738644-F196-11D0-9953-00C04FD919C1} and APPID {61738644-F196-11D0-9953-00C04FD919C1} to the user DOMAINNAME\spfarm SID (S-1-5-21-123456789-123456789-123456789-1157) from address LocalHost (Using LRPC). This security permission can be modified using the Component Services administrative tool.

To Fix This Error:
Follow the same steps as shown above except:

  • Step 3: 61738644-F196-11D0-9953-00C04FD919C1
  • Step 8 and 11: IIS WAMREG admin Service
  • Step 13: SharePoint Farm Account

CLSID 000C101C-0000-0000-C000-000000000046


Description: The machine-default permission settings do not grant Local Activation permission for the COM Server application with CLSID {000C101C-0000-0000-C000-000000000046} and APPID {000C101C-0000-0000-C000-000000000046} to the user DOMAINNAME\spfarm SID (S-1-5-21-123456789-123456789-123456789-1157) from address LocalHost (Using LRPC). This security permission can be modified using the Component Services administrative tool.

To Fix This Error:
Follow the same steps as shown above except:

  • Step 3: 000C101C-0000-0000-C000-000000000046
  • Step 4: Instead of searching, navigate to: HKEY_CLASSES_ROOT\Wow6432Node\AppID\{000C101C-0000-0000-C000-000000000046}
  • Step 8: (Value Not Set)
  • Step 11: The DCOM Application ID will be named by its CLSID/APPID instead of short name: {000C101C-0000-0000-C000-000000000046}
  • Step 13: If “SharePoint Farm Account” is not listed, add DOMAINNAME\spfarm and then add the rights.

C# Express – Create a Dummy or Placeholder Windows Service for Monitoring

Creating my custom service in Visual Studio

The IT ecosystem is rich with network monitoring systems (NMS). Each NMS has different capabilities, costs, and purposes in life. It is commonplace for me to come into a business that has invested in an NMS that doesn’t fit all their needs. You might ask, “What does this have to do with creating a Windows service?” Here is the scenario that brought this up.

A client has a monitoring solution for their Windows servers and some basic network up/down stats. Their internet connection had been flaky for a month or two. As we worked with their ISP, their connection continued to stay up but latency would spike and often drop packets. The monitoring never sees the link as down but the level of service is degraded and mostly unusable. The ISP can quickly reset the ports and fix the issue, but we want to know right when this happens to minimize downtime.

I setup a powershell script with the help of the team at ComputerPerformance.  This script is pretty straight forward. It uses the Test-Connection cmdlet and averages the latency to a remote host.

# Gets the average latency between you and $Server
# Using IP Addresses is recommended
$Server = "8.8.8.8"
$PingServer = Test-Connection -count 20 $Server
$Avg = ($PingServer | Measure-Object ResponseTime -average)
$Calc = [System.Math]::Round($Avg.average)
If ($Calc -gt 100 -Or $Calc -eq 0) {stop-service MyService} Else {start-service MyService}

Now, for the tricky part. How do I create a service that I can start and stop without actually impacting the underlying OS? I won’t go into the code too much but I have included the example C# source files in a zip at the bottom. I got this code from a MSDN social forum post.

To implement this, first make sure you read the forum post. You will need Visual Studio 2010 C# Express. Create a Windows Form Application and include references (Project –> Add References –> .NET) to System.Configuration.Install and System.ServiceProcess. You will need three files in your project: MyService.cs, MyServiceInstaller.cs and Program.cs. These are included in a zip at the end of this article (I also included the executable from the code if you want to test it out). You really only need to edit the MyService.cs and MyServiceInstaller.cs to match the Service’s purpose in life (and write useful event log entries). Once that is done, build the program. You will get an error on build about a “Windows Service Start Failure” as shown below. (Any developers out there know how to make this build w/o throwing the obvious error?) Just ignore the error and grab the executable from the Debug folder of the project. Place the executable somewhere safe (I use %windir%\SysWOW64\ in my example below).

Next, we need to install the service. You can install the service using the SC command in Windows. In this example, I used the name “lattest” as the service name and defined the display name as well. You can find more information on the SC.exe command here. Note: those spaces after the equals (=) sign are required when using the SC command.  Here is the code I used to install this service on Server 2008 R2:

sc create lattest binpath= "C:\Windows\SysWOW64\MyService.exe" displayname= "Latency Test" start= auto

At this point, your script can be setup to run as a scheduled task to start or stop the service depending on the conditions you set. You can point your NMS to monitor the service and you can sleep peacefully at night knowing you are proactively monitoring the issue.

If this is temporary in nature and you want to remove the service, just remove it from your NMS, delete the service and executable and remove your scheduled task. The service can be removed by running:

sc delete lattest

Here is the code from the Visual Studio Project: MyService.zip

Retrieving Password from Application Pool

I came across an undocumented app the other day. For a number of reasons, we needed to restore the password but it wasn’t documented anywhere. Luckily, the service account was setup in an app pool. In IIS 7.0 or 7.5, APPCMD can be used to recover the password. In 6.0, adsutil.vbs can be used.

cscript.exe /nologo adsutil.vbs GET W3SVC/AppPools/AppPoolName/WAMUserPass

However, I wanted to write my own little script. Having a little tidbit makes it easy to reuse later for other clients. For example, I could search AD for SPNs starting with “HTTP”, loop through each of their app pools and document the username and passwords for all service accounts used in this fashion. So, here is the little tidbit I threw together.

Option Explicit
 
Call GetAppPoolUserAndPass("localhost", "ApplicationPoolName")
 
Private Sub GetAppPoolUserAndPass (byVal strComputer, byVal strAppPool)
	Dim appPool
	On Error Resume Next
	Set appPool = GetObject("IIS://" & strComputer & "/w3svc/AppPools/" & strAppPool)
	If Err Then
		wscript.echo "Error connecting to " & chr(34) & strAppPool & chr(34) & " on " & strComputer
	Else
		wscript.echo strAppPool & vbTab & appPool.WAMUserName & vbTab & appPool.WAMUserPass
	End If
	On Error GoTo 0
End Sub

Here is an example of just what I mentioned above. YMMV but this should discover IIS boxes and report all the accounts used in their app pools. Note: Pools using built-in accounts will show up with blank passwords; this is normal; the password isn’t actually blank.

Option Explicit
 
' Determine DNS domain name.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
 
' Determine DNS domain name.
Dim objRootDSE, strDNSDomain
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
 
' Use ADO to search Active Directory.
Dim adoCommand, adoConnection
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection
 
' Build Query
Dim strBase, strFilter, strAttributes, strQuery
strBase = "<LDAP://" & strDNSDomain & ">"
strFilter = "(servicePrincipalName=HTTP*)" 'Search for SPN starting w/ HTTP (case insensitive)
strAttributes = "name"
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
 
Dim adoRecordset
Set adoRecordset = adoCommand.Execute
 
If (adoRecordset.EOF = True) Then
    Wscript.Echo "No SPNs Found matching HTTP*"
    Wscript.Quit
End If
 
Wscript.Echo "Computer Name" & vbTab & "AppPool Name" & vbTab & "User Name" & vbTab & "User Password"
 
Do Until adoRecordset.EOF
    Call GetApplicationPools(adoRecordset.Fields("name").Value & "." & strDNSDomain)
    adoRecordset.MoveNext
Loop
adoRecordset.Close
 
' Clean up.
adoConnection.Close
 
Private Sub GetApplicationPools (byVal strComputer)
	Dim objWMIService, colItems, objItem
 
	On Error Resume Next
	Set objWMIService = GetObject("winmgmts:{authenticationLevel=pktPrivacy}\\" & strComputer & "\root\microsoftiisv2")
	Set colItems = objWMIService.ExecQuery("Select * from IIsApplicationPoolSetting")
	If Err Then
		wscript.echo "Error connecting to " & strComputer
	Else
		For Each objItem in colItems
			Wscript.Echo strComputer & vbTab & objItem.Name & vbTab & objItem.WAMUserName & vbTab & objItem.WAMUserPass
		Next
	End If
End Sub

The Power of Scripting: Finding Morto.A

Here I go on another vbScript tutorial.  You might ask why I’m not doing this in powershell yet and it is simple: I still run into 2003 and XP environments. Oh yeah, and this works. I don’t care what scripting language I’m writing in if it gets the job done; you shouldn’t either. My $0.02. If you want to download this script, click here: Morto.A Detection Script.

A had to do a little cleanup on a network from the Morto.A worm.  The first thing I wanted to do was find out how bad things were.  They were reporting a DDOS across their LAN (mostly 3389) and a lot of other issues.  It as obvious we were going to need to rebuild a few systems but we wanted to get a grasp out of what the damage was.  This were generally working: logons, shares, etc.

I’m not going to go over what we did on the firewall or local network but discuss a quick script I threw together to scan the network for infected systems.  The trick was this network had multiple domains and several computers that weren’t even domain joined.

So, I put my automation hat on and threw together a script I will outline below.  I split this into sections to help you see how you can use scripting to piece together a complicated job in simple tasks.  It is pretty basic.  I start by defining what I want to do:

Problem statement: I need to check every computer in each domain for infection of the Morto.A worm.  I can split this into three distinct steps:

  1. For Each Domain
  2. Get Each Computer
  3. Check for Morto.A

For Each Domain

This is pretty simple.  There are advanced techniques for finding all the domains in a forest or reading from a text file or even a spreadsheet.  I like to keep it simple and just create an array.

Dim arrDomains
arrDomains = Array("domain1.domain.local", "domain2.domain.local", "domain3.domain.local")
For Each Domain in arrDomains
	Call ComputersAll(Domain)
Next

Get Each Computer

Now, I need to build the “ComputersAll” sub-routine.  I call this in the domain script by passing each domain in DNS format.  I used DNS domains in my example on purpose (you could use the DistinguishedName format “dc=domain1,dc=domain,dc=local” but I prefer DNS names for this purpose).  By default, each computer in that domain is going to register itself in DNS (assuming you set it up properly).  I want to get the computer name out of AD and append the dns domain name.  Once that is done, I want to use my “IsConnectible” script to check and make sure it is online.  If it pings, I should be able to carry out my business and find out if it is infected.

The real magic is in the lines: strBase, strAttrs and strFilter.  strBase sets the search base to the domain you sent the sub-routine.  It isn’t going to go outside this domain for its search but it will search the whole domain due to its use of subtree.  The search a specific OU, you have to use the DN format and that is out of scope of this article.  The strAttrs is pretty straight forward.  This is an array of attributes you want returned.  You could do DNSDomainName but some clients set this improperly.  It is safe to assume (in most cases) that the name and the domain name comprise the DNS domain name.  The strFilter isn’t doing much but may look complex.  Basically, it is looking for computers in AD that aren’t disabled.

The other things to pay attention to is the line after

Do Until ADORecordSet.EOF

.  This checks first if the computer is on the network through my “IsConnectible” script.  It passes the FQDN by appending “.” and the domain name to the name attribute from the query.

Const adUseClient = 3
Private Sub ComputersAll(byVal strDomain)
	Set adoCommand = CreateObject("ADODB.Command")
	Set adoConnection = CreateObject("ADODB.Connection")
	adoConnection.Provider = "ADsDSOObject"
	adoConnection.cursorLocation = adUseClient
	adoConnection.Open "Active Directory Provider"
	adoCommand.ActiveConnection = adoConnection
 
	strBase   =  ";"
	strFilter = "(&(objectClass=computer)(!userAccountControl:1.2.840.113556.1.4.803:=2));"
	strAttrs  = "name;"
	strScope  = "subtree"
	strQuery = strBase & strFilter & strAttrs & strScope
	adoCommand.CommandText = strQuery
	adoCommand.Properties("Page Size") = 5000
	adoCommand.Properties("Timeout") = 30
	adoCommand.Properties("Cache Results") = False
 
	Set adoRecordset = adoCommand.Execute
 
	If adoRecordset.RecordCount > 0 Then
		' wscript.echo "Computers for " & strDomain & ": " & adoRecordset.RecordCount
		' Loop through every single computer in the domain
		adoRecordset.MoveFirst
		Do Until adoRecordset.EOF
			If IsConnectible(adoRecordset.Fields("name").Value & "." & strDomain) = "Online" Then Call DetectMorto(adoRecordset.Fields("name").Value & "." & strDomain)
			adoRecordset.MoveNext
		Loop
	End If
	adoRecordset.Close
	adoConnection.Close
End Sub

Check For Morto.A

This is the tricky part. I used several sources and found two distict characterisitcs of this work:

  1. C:\windows\system32\sens32.dll
  2. HKLM\System\WPA
    1. Key: sr
    2. Value: Sens

So, I need to check and see if a file and registry key exists in order to detect if the machine is infected.  There are a couple of caveats with this: 1) when checking if a file exists, the default response is true on error, 2) you need local admin rights to query the c$ share, and 2) the registry check relies on the remote registry service.  To overcome these caveats, we put error checking in.  If an error occurs, it assumes a manual check is needed.  We do this to err on the side of caution.  Of course, on a large network, this isn’t desirable.  Feel free to contact me if you need more advanced help.  Here is the sub-routine I came up with to do all of the above.  It is mean and nasty and isn’t exactly the kind of finesse I prefer but, it works…

First, I try writing a temp file (and deleting it if it succeeds). If that works, I should be able to detect if the file exists and connect to the remote registry. However, perhaps you are an admin that is paranoid and disables the remote registry service. Well, it will still detect an error and tell you to check manually. Of course, if you don’t have admin rights, it will also tell you to check remotely.

Private Sub DetectMorto(byVal strComputer)
	' Detects morto via several methods...
	Dim blnInfected : blnInfected = False
 
 
	' Requires admin rights to properly detect. Check for rights
	Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject")
	On Error Resume Next
	Dim TempFile : Set TempFile = objFSO.CreateTextFile("\\" & strComputer & "\c$\WINDOWS\tempfile.deleteme", True)
	TempFile.WriteLine("This is a test.")
	TempFile.Close
	Set TempFile = Nothing
	objFSO.DeleteFile("\\" & strComputer & "\c$\WINDOWS\tempfile.deleteme")
	If Err Then bnlInfected = "Error"
	Err.Clear
	On Error GoTo 0
 
	' Check for registry key placed by Morto...
	Dim strKeyPath, strEntryName, objReg, strValue
	strKeyPath = "SYSTEM\WPA"
	strEntryName = "sr"
	On Error Resume Next
	Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\default:StdRegProv")
	objReg.GetStringValue HKEY_LOCAL_COMPUTER, strKeyPath, strEntryName, strValue
 
	If Err Then blnInfected = "Error"
	If strValue = "Sens" Then blnInfected = True
 
	' Check for file indicating morto infection
	Dim strMortoSens32
	strMortoSens32 = "\\" & strComputer & "\c$\WINDOWS\system32\Sens32.dll"
	If objFSO.FileExists(strMortoSens32) Then blnInfected = True
 
	' If the Infected flag is set, it is infected...
	If blnInfected = True Then
		wscript.echo "*******MORTO INFECTION: " & strComputer
	ElseIf blnInfected = "Error" Then
		wscript.echo "Error (Check Manually): " & strComputer
	Else
		wscript.echo "Clean: " & strComputer
	End If
End Sub

Conclusion

So, I have taken several scripts and thrown them together to find a solution. I can reuse this for anything. Perhaps I want to use vbscript to find computers with a certain file on their hard drive. I can reuse this by just tweaking the Morto sub-routine.

IsConnectible: My vbScript Ping Method

Whenever I am doing large sweeps of the network that require connecting to a large number of workstations (e.g. file copy, wmi query, etc.), I prefer to check to see if I can even see the system. This avoids waiting for (WMI) timeouts and also aids in troubleshooting failures. If the file copy failed, why? Well, if I can’t ping it or it can’t be resolved, I would like to know right away and move on to the next host.

Of course, there are a couple downsides to this method. It does add overhead to the script because it too has a timeout. However, depending on the purpose of the script, this may be acceptable for the flexibility you gain. The other caveat is that the systems you run this against must allow ICMP on their local firewall or the script will just ignore them and move on to the next host.

There are several methods for pinging hosts but I’ve found this to be the most reliable since it works against any system that allows ICMP, even Linux or Macs. This is adapted from Richard Mueller’s ping script. This method will return three possible values: “Online”, “No Ping Reply”, or “No DNS/WINS Entry”. You can also tweak the ping command options to your liking.

Here is an example of how to call the function:

Dim computers(2), computer, pingable
computers(0) = "pc-100.domain.local"
computers(1) = "pc-200.domain.local"
comptuers(2) = "pc-300.domain.local"
For Each computer In computers
	Select Case IsConnectible(computer)
		Case "Online"
			wscript.echo computer & " is online"
		Case "No Ping Reply"
			wscript.echo computer & " is offline or firewall blocks ICMP"
		Case "No DNS/WINS Entry"
			wscript.echo computer & " cannot be found in DNS/WINS"
		Case "Host Unreachable"
			wscript.echo computer & " is unreachable"
	End Select
Next

Here is the function:

Private Function IsConnectible(ByVal strComputer)
	' Uses ping.exe to check if computer is online and connectible.
	' Adapted from http://www.rlmueller.net/Programs/Ping1.txt
	Dim objShell, objExecObject, strText
	Set objShell = CreateObject("Wscript.Shell")
 
	' use ping /? to find additional values for ping command; see -n and -w
	Set objExecObject = objShell.Exec("%comspec% /c ping -n 2 -w 750 " & strComputer)
	Do While Not objExecObject.StdOut.AtEndOfStream
		strText = strText & objExecObject.StdOut.ReadLine()
	Loop
 
	If InStr(strText,"could not find host") > 0 Then
		IsConnectible = "No DNS/WINS Entry"
	ElseIf (InStr(strText,"Reply from ") > 0) And (InStr(strText,": bytes=") > 0) Then
		IsConnectible = "Online"
	ElseIf InStr(strText,"Destination host unreachable") > 0 Then
		IsConnectible = "Host Unreachable"
	Else
		IsConnectible = "No Ping Reply"
	End If
End Function

Microsoft Releases Windows 8 Developer Preview

Microsoft has released the Windows 8 Developer Preview.  This download is a full version of the pre-beta Windows 8 build and is chock full of disclaimers regarding its stability.  Needless to say, I had to download it and give it a shot.  The download (2.8GB to 4.8GB) can be found linked off the front page of the Windows Dev Center.  I decided to download the full version with all the Metro development goodness though there is a lighter version without all the developer tools.

The Windows 8 Preview Guide (PDF) is pretty impressive.  It is a nice, clean overview of Windows 8.  Of course, the net is going to be saturated with info in just a few days now that it is publicly available.  I also highly recommend checking out the Build Keynote which provides some of the eye candy you can look forward to.

I wasn’t as surprised to see ARM support as Microsoft has made it clear it was coming.  I was surprised to see a 32-bit version for download.  I suppose it might be a bit lighter weight (at .8GB < the x64 version) for those just wanting to pull it up in a VM to give it test run.

I was excited when I saw the Live Connect technical preview (site doesn’t work w/ Chrome) until I realized it is only the SDK.

Installing Exchange 2010 Service Pack 1 Fails At Mailbox Role: Database is mandatory on UserMailbox.

In a recent incident, an Exchange server had a complete volume failure during testing. Exchange 2010 was reinstalled but when installing Service Pack 1, it failed upgrading the Mailbox Role. Upon reviewing the log, I found the following line:

Database is mandatory on UserMailbox. Property Name: Database

The error doesn’t explain the problem very well but it is basically saying that there is a UserMailbox without a database, which should never happen. The failure of the volume and subsequent reinstall of 2010 left the arbitration mailboxes (and one or two user mailboxes) orphaned. Most of the suggestions to resolve this problem list doing things like deleting the system mailboxes and running “setup.com /PrepareAD”. After looking around, I was able to parse together a few other options and find a fix.

First, do a search in AD for the System mailboxes and make sure they exist in AD. (If they do not exist, check out this blog.)The three mailboxes are:

  • Discovery – SystemMailbox{e0dc1c29-89c3-4034-b678-e6c29d823ed9}
  • Message Approval – SystemMailbox{1f05a927-xxxx-xxxx-xxxx-xxxxxxxxxxxx} (where x is a random number)
  • Federated E-mail – FederatedEmail.4c1f4d8b-8179-4148-93bf-00a95fa1e042

Next, check out the status of their mailboxes:

Get-Mailbox –Arbitration

For this client, their Discovery and Message Approval mailboxes spat out error messages:

WARNING: The object XXXXXXXX.XXXXX/Users/SystemMailbox{e0dc1c29-89c3-4034-b678-e6c29d823ed9}
has been corrupted, and it's in an inconsistent state. The following validation errors happened:
WARNING: Database is mandatory on UserMailbox.

The fix is a lovely, one-line powershell. It won’t do anything without prompting you first. To verify it fixes the issue after you run it, take the first half of the command (get-mailbox -arbitration) and run that again to confirm they are online and okay.

Get-Mailbox -Arbitration | Set-Mailbox -Arbitration –Database "Mailbox Database XXX"

Hopefully this saves somebody from causing a bigger mess than necessary. After running this, I was able to install Service Pack 1 just fine. YMMV.

Edit: I found the DiscoverySearchMailbox{D919BA05-46A6-415f-80AD-7E09334BB852} was orphaned as well. To fix this mailbox, I just ran the following PoSH.

Get-Mailbox -Identity "DiscoverySearchMailbox{D919BA05-46A6-415f-80AD-7E09334BB852}" | Set-Mailbox –Database "Mailbox Database XXX"

Exchange 2007+: Aliases have invalid data

Twice in the past two weeks, I have come across Exchange 2003 to Exchange 2007 migrations which went uncompleted. In both cases, I received the following error(s) when trying to view the properties of a recipient with spaces in its alias or when viewing the properties of the offline address book:

  • The properties on have invalid data. If you click OK, default values will be used instead and will be saved if you do not change them before hitting Apply or OK on the property page. If you click cancel, the object will be displayed read-only and corrupted values will be retained. The following values have invalid data: Alias.
  • WARNING: Object has been corrupted and it is in an inconsistent state. The following validation errors have been encountered: WARNING: is not valid for Alias.
  • Set- : is not valid for Alias.

Here is a screenshot of the error:

Exchange 2003 would allow an administrator to put spaces in the Alias attribute. That poses a problem for 2007 which is strict about the characters it allows in this attribute. In Exchange 2007 the following characters are considered valid: Strings formed with characters from a to z (uppercase or lowercase), digits from 0 to 9, !, #, $, %, &, ‘, *, +, -, /, =, ?, ^, _, `, {, |, } or ~. But, no spaces.

Going through you recipients one by one is a daunting task. Here is some code to automate this cleanup. Once you take care of this, you shouldn’t run into it again since the tools in Exchange 2007 won’t let you make the same mistake.

Clean up mailboxes:

Get-Mailbox | Where {$_.Alias -like "* *"} | ForEach-Object {Set-Mailbox $_.Name -Alias:($_.Alias -Replace " ","")}

Clean up public folders:

Get-PublicFolder | Where {$_.Alias -like "* *"} | ForEach-Object {Set-PublicFolder $_.Name -Alias:($_.Alias -Replace " ","")}
Get-PublicFolder -Identity "\" -Recurse -ResultSize Unlimited | Foreach { Set-PublicFolder -Identity $_.Identity -Name $_.Name.Trim()}

Clean up contact objects:

Get-MailContact -ResultSize unlimited | foreach {$_.alias = $_.alias -replace '\s|,|\.'; $_} | Set-MailContact
Get-Contact | Where {$_.Alias -like "* *"} | ForEach-Object {Set-Contact $_.Name -Alias:($_.Alias -Replace " ","")}

Clean up distribution groups:

Get-DistributionGroup | Where {$_.Alias -like "* *"} | ForEach-Object {Set-DistributionGroup $_.Name -Alias:($_.Alias -Replace " ","")}

Check for any objects that still throw errors:

Get-PublicFolder | findstr "Warning"
Get-Contact -resultsize unlimited | findstr "Warning"
Get-Mailbox -resultsize unlimited | findstr "Warning"
Get-DistributionGroup -resultsize unlimited | findstr "Warning"

Rebuild your address lists:

Set-AddressList "All Users" -IncludedRecipients MailboxUsers
Set-AddressList "All Groups" -IncludedRecipients Mailgroups
Set-AddressList "All Contacts" -IncludedRecipients MailContacts
Set-AddressList "Public Folders" -RecipientFilter {RecipientType -eq "PublicFolder"}
Set-GlobalAddressList "Default Global Address List" -RecipientFilter {(Alias -ne $null -and (ObjectClass -eq 'user' -or ObjectClass -eq 'contact' -or ObjectClass -eq 'msExchSystemMailbox' -or ObjectClass -eq 'msExchDynamicDistributionList' -or ObjectClass -eq 'group' -or ObjectClass -eq 'publicFolder'))}