Home Lab…Complete!

July 30th, 2010 by Steve No comments »

Home Lab - Logical View

I am very excited as I finally got my home lab complete!  Check it out and tell me what you think.

Perimeter switch, internal switch, and WAP

8 TB NAS (iSCSI Support), cable modem, and UPS

ESXi 4.x Host (1x Quad-Core, 16 GB RAM)

Windows 2008 R2 – File Management Tasks

March 10th, 2010 by Steve No comments »

There is a really neat post on Adi Oltean’s Blog concerning the use of Windows 2008 R2′s File Management Tasks (FMTs) to archive data.  He uses a “Custom” task type and refers to a batch script which moves files and leaves a symbolic link.  This is sort of a “poor man’s” HSM solution, admittedly, but still pretty cool and instructive as to what can be accomplished with FMTs (anything you can script!).  His script is below:

if exist "c:\protected\%~pnx1" @echo Target file already exists! & goto :EOF 
md "c:\HSM\%~p1" 
move %1 "c:\protected\%~p1" 
mklink %1 "c:\protected\%~pnx1"

If you are wondering (like I was) what the heck “%~p1″ or “%~pnx1″ means, check out this site.

I set up a similar FMT in my test environment to learn about this technology, but I had problems with Adi’s batch script.  It was hard to debug because it has no logging, so I wrote my own in VBS with lots of logging.  You can download my script here.  Here is how I set up my FMT.

1.  On the General tab enter a task name and the Scope.  The scope is where the FMT run against.

2.   On the Action tab choose “Custom” for the Type.  For the Executable section enter the path to cscript.exe.  In the Arguments section enter the path to the script (download above), and choose the [Source File Path] variable to insert.  Command Security should be set to Local System.

3.  On the Condition tab place a check mark inside the Days since file was last accessed box.  Note the property conditions section of this tab.  Here you can add file classifications you have previously set up.  For a great read on Microsoft’s File Classification Infrastructure read the Storage Team’s blog about itNote, if you want to use “Last Accessed” time for your FMT as I did you need to enable the tracking of this attribute.  This is done by setting HKLM\System\CurrentControlSet\Control\FileSystem\NtfsDisableLastAccessUpdate to 0 (this value is REG_DWORD).  Note that this could impact disk IO performance on busy file servers!

4.  On the Schedule tab enter whatever schedule/frequency is desired.

Finally, use a Windows “Touch” utility (download one here) to alter the Last Accessed date of a file that falls within the scope of the FMT you created.  Then manually run your FMT (Right-click > Run Now) and if all is well the file you altered should be moved and a symbolic link left in it’s place.

System Center Operations Manager 2007 R2 – How to Install a Gateway Server

March 10th, 2010 by Steve No comments »

Installing a Gateway server in your existing OpsMgr environment is a fairly challenging task.  When accomplishing this task for a customer I found many resources which helped, but I could not find one that was complete.  The process I found which was the most helpful was Brad Hearn’s blog.  Much of my documented process comes from his document.  Honestly I would never have gotten my gateways operational without Brad’s excellent post so many thanks!

Download “How to Install a Gateway Server.pdf” here.

OpsMgr 2007 DMZ-Based Agents Fail to Report to Gateway with Event ID 20070

February 19th, 2010 by Steve No comments »

We recently noticed most of our DMZ-based OpsMgr agents were not connecting to their gateway server.  On the agent we saw the following event:

Event Type:          Error
Event Source:       OpsMgr Connector
Event Category:    None
Event ID:              20070
Computer:            <Computer>
Description:          The OpsMgr Connector connected to <domain>, but the connection was closed immediately after authentication occurred.  The most likely cause of this error is that the agent is not authorized to communicate with the server, or the server has not received configuration.  Check the event log on the server for the presence of 20000 events, indicating that agents which are not approved are attempting to connect.

On the gateway server the following event was being logged:

Event Type: Information
Event Source:        OpsMgr Connector
Task Category: None
Event ID:      20000
Description: A device which is not part of this management group has attempted to access this Health Service.  Requesting Device Name : <computer>
The strange thing is that these agents had been working fine, and a few still were working!  We checked the usual things and did the usual recovery steps:
  • Is TCP 5723 open to the gateway server?
  • Restart the HealthService
  • Is agent in Pending Management?
  • Restart the HealthService
  • Wait 5 minutes
  • Restart the HealthService

All to no avail.  We found http://blogs.technet.com/operationsmgr/archive/2009/02/17/opsmgr-2007-port-requirements-for-scom-agents-in-a-dmz.aspx which suggested opening ports 88 and 389 from the agent to the RMS. This did not make sense to us since some agents were working.  So we used Netmon 3.3 to trace the client while the HealthService starts.  It never used any port but 5723.

We even enabled verbose diagnostic tracing (http://support.microsoft.com/kb/942864) and reviewed the logs.  We saw where the 20070 event was being generated but not much interesting besides that:

5412.5956::02/19/2010-10:46:56.978 [Common] [] [Verbose] :Common::EventLogUtil::LogEvent{EventLogUtil_cpp311}Logging error event 20070 with args “<servername>”, “NULL”,”NULL”, “NULL”, “NULL”, “NULL”, “NULL”, “NULL”, “NULL”

5412.5956::02/19/2010-10:46:56.978 [Common] [] [Information] :Common::EventLogUtil::LogEvent{EventLogUtil_cpp397}Logging event 20070 from source “OpsMgr Connector” with severity Error and description “The OpsMgr Connector connected to <GatewayServer>, but the connection was closed immediately after authentication occurred.  The most likely cause of this error is that the agent is not authorized to communicate with the server, or the server has not received configuration.  Check the event log on the server for the presence of 20000 events, indicating that agents which are not approved are attempting to connect.”.

Solution…

We finally had to call Microsoft.  After about 30 minutes of troubleshooting the engineer saw that the OpsMgrConnector.Config.xml file in the C:\Program Files\System Center Operations Manager 2007\Health Service State\Connector Configuration Cache\<MgmtGrpName> folder on the gateway server was last modified several weeks ago.  He had us rename the Health Service State folder under C:\Program Files\System Center Operations Manager 2007 and restart the HealthService.  After this a new Health Service State folder was created and the OpsMgrConnector.Config.xml had a much more current last modified date.  We then restarted the HealthService on the agents and they reported in to the gateway server correctly.

Extend System Center Configuration Manager 2007 to Collect Fibre Channel HBA Information – Revised

January 6th, 2010 by Steve 11 comments »

Version 2…

In my original post on this subject I described how to set up ConfigMgr to grab data from the MSFC_FCAdapterHBAAttributes class under Root\wmi.   Later I found out that, as least in my environment, the data in this class was unreliable.  It would literally be there one day and the next it would have disappeared.  So I had to change my approach.  This new method of getting HBA info into ConfigMgr is not exactly elegant, but it is effective.  Use it at your own risk! The process is as follows:

  1. Install Microsoft’s FCInfo utility on your machines with HBAs.  I packaged this up and deployed to a collection populated with these machines.  Note that the install will throw an error on Windows Server 2008 but the utility still works and it MUST be present for this process to work!
  2. Update sms_def.mof to look for HBA info in a new class called Custom_HBA_Info (later steps actually create this class).  Add the below text to your sms_def.mof (always make a backup first!).

#pragma namespace ("\\\\.\\root\\CIMv2\\sms")
[SMS_Report(TRUE),
SMS_Group_Name("Custom_HBA_Info"),
SMS_Class_ID("Microsoft|Custom_Frost_HBA_Info|1.0"),
Namespace("\\\\\\\\.\\\\root\\\\CIMv2")]
class Custom_HBA_Info : SMS_Class_Template
{
[SMS_Report(TRUE), key ]
string	Adapter;
[SMS_Report(TRUE)]
string	NodeWWN;
[SMS_Report(TRUE)]
string	PortWWN;
[SMS_Report(TRUE)]
string	SerialNumber;
[SMS_Report(TRUE)]
string	DriverName;
[SMS_Report(TRUE)]
string	DriverVersion;
[SMS_Report(TRUE)]
string	FirmwareVersion;
[SMS_Report(TRUE)]
datetime DateCollected;
};

Almost immediately after saving the sms_def.mof file ConfigMgr will compile it.  You can monitor the success/failure of this in the dataldr.log file on the ConfigMgr server (<install_dir>\Logs).

3.  Download my script (rename to GetHBAInfo.vbs)  to a share on your network.  The script creates the WMI class referenced above, runs fcinfo.exe, grabs the output, and populates it into Custom_HBA_Info.

4.  Create a Software Distribution package for the script.  Create a Program for the package with the following command line: %systemroot%\system32\cscript.exe GetHBAInfo.vbs

5.  Schedule a recurring advertisement associated with a collection containing all your machines with HBAs.  My advertisement runs once per week.

Thats it.  Now, to be sure it is working:

1.  Run your advertisement so that the script runs on your agents with HBAs.

2.  On one of those computers use wmic to validate the presence of the namespace.  Command syntax:

wmic path Custom_HBA_Info

If an Invalid Class error is displayed then either the script has not run or it has an error.  The script logs it’s results under %windir%\Temp in a file that starts with GetHBAInfo_<date>_<time>.log.

3.  Force a couple of agents to run their hardware inventory.  Monitor the dataldr.log on the site server.  You should see lots of data flying by as the agent updates it hardware info.  When complete search for the string “Custom_HBA_Info”.  If you find it then the data should have gotten put in your site database.  Look for a table in the database called dbo.Custom_HBA_Info_Data.  If it exists then you should be golden.

4.  Use Resource Explorer to view one of your machines with HBAs.  Under Hardware you should see Custom_HBA_Info, and your data should be there.

Special thanks to my co-worker Jason Sandys, a ConfigMgr MVP.  Without his assistance I would not have gotten this to work.

Return HBA World Wide Name from WMI

December 16th, 2009 by Steve 1 comment »

I searched quite a bit looking for a way to get an FC card’s WWN from WMI.  I found some information indicating it might be in the root\WMI namespace so I used Scriptomatic 2.0 to look through the classes in that namespace until I finally found it.  It was in QL_FibrePortNPIVAttributes (I assume this classis added by the QLogic driver installation…yeah the QL gave it away…).

Unfortunately the numbers of the WWN are returned in decimal rather than in hex, the digit groups are returned separated by commas, and single digits are used when the number is below 10.  So it looks like this:

WWPN: 80,6,11,0,0,194,154,2

Well, we can’t have that!  So I wrote a script to grab the information and convert it hex, group digits with a colon and “pad” an extra zero if the decimal value was under 10.  Here is the script:

On Error Resume Next

Const wbemFlagReturnImmediately = &h10
Const wbemFlagForwardOnly = &h20

arrComputers = Array(".")
For Each strComputer In arrComputers
	Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\WMI")
	Set colItems = objWMIService.ExecQuery("SELECT * FROM QL_FibrePortNPIVAttributes", "WQL", _
                                          wbemFlagReturnImmediately + wbemFlagForwardOnly)
	For Each objItem In colItems
		var1 = objItem.WWPN
		For i = 0 To UBound(var1)
			If len(Hex(var1(i))) < 2 then
				var2 = "0" + Hex(var1(i))
			Else
				var2 = Hex(var1(i))
			End If
			tmpVar1 = tmpVar1 & ":" & var2
			tmpVar2 = mid(tmpVar1, 2)
		Next
		wscript.echo tmpVar2
		tmpVar1 = ""
		tmpVar2 = ""
	Next
Next

This returns a beautifully formatted (yes I am a geek) WWN…observe:

50:06:0B:00:00:C2:9A:00

Printer Migration Client Script

November 3rd, 2009 by Steve No comments »

If you have ever had to migrate all the printers from one Windows print server to another, the server side part is pretty easy.  Windows 2008 includes the Printer Migration Wizard which can migrate the queues.  Prior to Windows 2008 there was an outstanding utility called Print Migrator (PrintMig) which made it a snap.

However the client side is a bit more tricky.  Since there is a different server name in the printer share path the clients will be broken after the migration.

Printer share  path on old server: \\OldPrnSrv\Printer1

Printer share path on new server: \\NewPrnSrv\Printer1

This problem can be further complicated if during the migration you took the opportunity to standardize Printer/Printer Share names.  I had this exact problem at a client.  I solved it with a GPO-based logon script and input file.  Before I go into how to implement this, first a little about the script.

  • The script first checks for the existence of a “check” file.  If the check file exists then we assume the script already ran and we exit.
  • Then the script records the user’s default printer as it will need this info later to ensure the same device is set as default after the printer reconnect.
  • Next the script walks through the input file and attempts to disconnect each “old” printer connection and reconnect to the new.  If the printer share in the input file is not defined on the person’s machine then it skips that line and moves on to the next line/printer.
  • Once all the input file has been traversed the script resets the person’s default printer and creates the “check” file.

Here is the script code.

On Error Resume Next
Const ForReading = 1

Set WshNetwork = CreateObject("WScript.Network")
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists("c:\PrinterReconnectFinished.txt") then
Set f1 = fso.OpenTextFile(GetPath() & "input.txt", ForReading)

varDefault = GetDefaultPrinter()

tmpArr = Split(f1.readall, vbcrlf)
for i = 0 to UBOUND(tmpArr)
    If instr(1, tmpArr(i), varDefault, 1) then x = i
    err.clear
    tmpVar = split(tmpArr(i), "~")
    WshNetwork.RemovePrinterConnection tmpVar(0)
    If err.number = 0 then WshNetwork.AddWindowsPrinterConnection tmpVar(1)
next

var1 = split(tmpArr(x), "~")
ConfigDefaultPrinter(var1(1))
    Set f2 = fso.CreateTextFile("c:\PrinterReconnectFinished.txt", True)
    Set f3 = fso.Getfile("c:\PrinterReconnectFinished.txt")
    f3.attributes = f3.attributes + 2
End If

'*************************************************************************************************
Sub ConfigDefaultPrinter(name)
        '*****************************************************************************************
        '*****************************************************************************************
        ' Purpose:  This sub routine defines a default printer based on the printer name passed to
        ' it.
        ' Version 1.0
        ' Arguements:  None
        '*****************************************************************************************
        '*****************************************************************************************
    strComputer = "."
    Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & _
    strComputer & "\root\cimv2")
    Set colInstalledPrinters =  objWMIService.ExecQuery _
    ("Select * from Win32_Printer Where Name = 'name'")
    For Each objPrinter in colInstalledPrinters
            objPrinter.SetDefaultPrinter()
    Next
End Sub
'*************************************************************************************************

'*************************************************************************************************
Function GetDefaultPrinter()
        '*****************************************************************************************
        '*****************************************************************************************
        ' Purpose:  This Function returns the default printer as configured on the client.
        ' Version 1.0
        ' Arguements:  None
        ' Returns:  Text string
        '*****************************************************************************************
        '*****************************************************************************************
    strComputer = "."
    Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & _
    strComputer & "\root\cimv2")
    Set colInstalledPrinters =  objWMIService.ExecQuery("Select * from Win32_Printer")
    For Each objPrinter in colInstalledPrinters
        If objPrinter.Default then
            GetDefaultPrinter = objPrinter.Name
        End If
    Next
End Function
'*************************************************************************************************

'*************************************************************************************************
Function GetPath()
    '*********************************************************************************************
    '*********************************************************************************************
    ' Purpose:  This Function returns the path where the script is currently being executed.
    ' Version 1.0
    ' Arguements:  None
    ' Returns:  Text string
    '*********************************************************************************************
    '*********************************************************************************************
    Dim path
    path = WScript.ScriptFullName
    GetPath = Left(path, InStrRev(path, "\"))
End Function
'*************************************************************************************************

Here’s how you can implement this solution.

1. Create an input file and put each old printer share path and new share path on a new line separated by a “~”.  It should look like this:

\\OldPrnSrv1\Printer1~\\NewPrnSrv1\Printer1
\\OldPrnSrv1\Printer2~\\NewPrnSrv1\Printer1
etc...

2. When you have all the printer share paths entered in your input file save it as input.txt.

3. Next download the printer migration script here.  Strip the “.txt” off of the end of the name.

4. Save the input.txt and script files in the domain scripts share (\\mydomain.com\SYSVOL\mydomain.com\scripts).

5. Create a new Group Policy Object (GPO) called Printer Reconnect. NOTEDon’t link it to any container yet.

6. Edit the GPO under User Configuration>Windows Settings>Scripts double-click Logon.

7. Click the Add button, then Browse.  Locate/select the PrinterReconnect.vbs script in the path you saved it to previously.

8. Click OK and make sure the script is displayed on the Logon Properties screen.  Click OK.

Once all printers are migrated to the new server and well tested, you should be ready to have the clients reconnect to the migrated queues on the new server.  ONLY when ready to have clients reconnect, go to the next step.

9. Link the Printer Reconnect GPO to an appropriate container to apply the logon script to targeted users.

As always, use this at your own risk.  Let me know if you have any issues and I will help out as I can.

Desire = Entitlement?

September 4th, 2009 by Steve 7 comments »

As I was listening to NPR while driving home yesterday (A thing I recommend be done only sparingly and with great vigilance) I heard about the battle being waged in Maine over same-sex marriage.  You can read the story here.  As I listened I thought about the audacity of a group that would attempt to change the definition of an institution which has been established and unchanged for millennia.  I wondered at the mind set that thinks a “thing” can be redefined merely because of its observer’s wish.  It seemed to me (and still does) that such a person might equally state that a rock is now an eggplant and that it would be so just because they desire it to be.  It is not as though such people are insane, i.e. they do not look at a rock and see an eggplant.  It is that they believe the identity or meaning of a “thing” has no reference outside of their wish or desire.  It is not perception so much as it is will.  A thing may be a thing only if they allow it to be.  It has no “thing-ness” outside of their desire/will.

I also thought about the word “entitlement”.  I never cease to be amazed at the sense of entitlement people can have.  Those who would change the definition of marriage would do so because they feel entitled to “marry” their partner and gain all the benefits there of.  I tried to trace this thought pattern back to it’s source, and I came back to desire.  It is as though we believe that if we desire something strongly enough or have desired it for long enough that somehow we “deserve” it or we are “owed” it.  If we want it, it must be good and right.  We begin to feel antagonistic toward those who would presume to deny us this desire.  If someone disagrees they must be ignorant, bigoted, or worse.

So some questions I have include:

  • At what point did reality begin to depend on our will/desire? Reality is what it is.  Reason dictates that a thing is what it is whether I like/want/appreciate/agree with it or not.  Certainly a thing cannot be “A” and “non-A” at the same time and in the same relationship.  The essence of a thing is not affected one little bit by my perception of it, belief in it or desire concerning it.
  • When was it established that desire would equate with entitlement? My desire for something does not equate to my being owed that thing…no matter how long I have wanted it nor how strongly I want it.  When I think about it clearly, I am owed precious little in life.

Some may object that in the case of marriage, it is not an “absolute” reality but rather a “societal” reality, or that marriage has no meaning outside of what a society defines.  Such a belief is convenient for those in a society who would change the meaning of marriage.  If they can achieve change through whatever course allowed by their particular society then it will be altered in actuality.  However such a belief comes from somewhere.  All ideas do.  In this case, most likely the society gave themselves the right to define marriage.  They assumed ownership of the definition.  Such self-empowerment may be appropriate when setting arbitrary laws such as a speed limit but is marriage arbitrary?  Does the history of marriage extend from before such a society was in place?  Of course it does.  Marriage was created and given definition at creation…by the Creator.  When some religious leaders of His day asked Jesus about the permanence of marriage, to what point did He refer His answer?  Did He quote Roman law?  No, He quoted Genesis:

And Pharisees came up to him and tested him by asking, “Is it lawful to divorce one’s wife for any cause?”  He answered, “Have you not read that he who created them from the beginning made them male and female, and said, ‘Therefore a man shall leave his father and his mother and hold fast to his wife, and the two shall become one flesh’? So they are no longer two but one flesh. What therefore God has joined together, let not man separate.” They said to him, “Why then did Moses command one to give a certificate of divorce and to send her away?”  He said to them, “Because of your hardness of heart Moses allowed you to divorce your wives, but from the beginning it was not so. And I say to you: whoever divorces his wife, except for sexual immorality, and marries another, commits adultery.” Matthew 19:3-9

So, concerning the definition of marriage, we would do well remember its origin, respect its creator and subjugate our own desires to His decree.

Server Inventory Script

August 5th, 2009 by Steve 3 comments »

As a consultant, many times I need to quickly gain information about the Windows servers in an environment. I’ve finally put something together to try and make my life easier. It is a script that opens Microsoft Excel, sets column definitions that seem useful to me, then populates the spreadsheet with a bunch of data.  The data is gathered from every Windows server that is a member of the Active Directory domain you specify.  Specifically, it gathers:

  1. Server Name
  2. Whether the server is online (ping’able) or not
  3. OS
  4. Service Pack
  5. Manufacturer
  6. Model
  7. Serial Number
  8. Whether it is a domain controller
  9. Whether it is a DNS server
  10. Whether it is a DHCP server
  11. Whether it is a WINS server (yes there are still a few of those)
  12. Whether it is a MSCS cluster node
  13. Whether it is an Exchange server
  14. What applications are installed (excluding Security Updates and Hotfixes)
  15. Whether WMI could be connected to

Dependencies

  • Microsoft Excel (any later version is fine)
  • Sysinternals PSTools
  • Admin rights on every server in the domain (Domain Admin rights would be easiest)

I wanted to use WMI exclusively but unfortunately it is very unreliable, therefore the script heavily depends on 2 PSTools (PSInfo and PSService).  You will need to download those and place them in a directory on the PC you run the script from.

Edits

The only lines you need to edit are 15 and 16, where you enter in your domain name (follow the format example!) and the path to your PSTools directory.

'your domain below
strDom = "DC=ACME,DC=COM"
pstoolsPath = "c:\Tools\pstools"

You can download the text of the script here or a zip file with the script here.  I hope others find it helpful.  As always, use this solution at your own risk.  If you have problems with the script, comment on the post and I will help when I have time.

How To Use Windows 2008 to Host Storage for ESX

July 8th, 2009 by Steve 8 comments »

Disclaimer

Let me stress before I begin that the below configuration is for testing only.  It involves insecure settings on the Windows 2008 server so do not use this information for a production solution.

Background

In an effort to learn about ESX 4.0, or vSphere, I set up 4 VMs within VMWare Workstation 6.5.2 using the below configuration:

  • 2 VMs to run ESX 4.0.  I used the instructions at xtravirt.com (get them here) to create the VMs.
  • 1 VM to run vCenter server.
  • 1 VM to serve as a domain controller.  vCenter cannot be installed on a domain controller, hence the need for another VM.  By the way, you don’t need a domain environment for vSphere, but I wanted one to test with.

All my installs went fine.  However problems arose when attempting to use the vCenter server (OS: Windows 2008) as my NFS server.  I had used Windows 2003 in the past with no issue for a similar set up so I was stuck for awhile. Google searches revealed others with the same issue but no solutions (that I could find).  I’m happy to report I did finally get it working…steps below.  The following assumptions apply:

  1. You have already added the File Server role with the Services for Network File System (NFS) role service and that you have an NFS share created.  For a walk-thru of this go here.
  2. Your ESX host’s have a VMKernel port properly configured to allow access to the NFS server.  Confirm the configuration is correct by vmkping’ing the NFS server from the host itself.

VMKPing

Steps to enable ESX hosts to access NFS share on Windows 2008.

  1. Edit the NTFS permissions of the shared folder to allow the ANONYMOUS LOGON group Full Control.
    1. AnonymousPermission
  2. On the NFS Sharing tab click the Manage NFS Sharing button.  Check the Allow anonymous access box.
    1. NFSTabNFSAdvancedSharing
  3. Click the Permissions button.  In the NFS Permissions dialog click Add.  Select Host and enter the IP address of your first ESX host.  Set the permissions to Read/Write and select the Allow root access box and click OK.  Repeat the proceedure for your other ESX host.
    1. NFSPermissionsAddHost
  4. Click OK three times then Close.  If a warning pops up about how insecure this configuration is, clickYes.  Remember, this is for testing only.
  5. Open the Local Security Policyeditor (Start>Administrative tools>Local Security Policy), expand Local Policies, and click Security Options.
  6. Locate the Network Access: Let Everyone permissions apply to anonymous userspolicy and make sure it is set to Enabled.
  7. Reboot the NFS server.  When it comes back up you should be able to mount the NFS share from the ESX host(s) within vCenter.