stichl.at tech at work

25Feb/150

vCenter refuses to delete empty cluster object

Today I wanted to remove an old cluster object in a vCenter server, but got this error followed by a vSphere Client disconnect.

A general system error occurred: Error(VdbODBCError) (-1) "ODBC error: (23000) - [Microsoft]
[SQL Server Native Client 11.0][SQL Server]The DELETE statement conflicted with the REFERENCE constraint "FK_VPX_COMP_DAS_VM_REF_VPX_COM". The conflict occurred in database "vCenter", table "dbo.VPX_COMPUTE_RESOURCE_DAS_VM", column 'COMP_RES_ID'." is returned when executing SQL statement "DELETE FROM VPX_ENTITY WITH (ROWLOCK) WHERE ID =?"

 

To resolve this issue you need to access the vCenter database using SQL.

First find out the ID of the entity which you are trying to delete:

SELECT ID FROM VPX_ENTITY WHERE NAME="2delete"

After that you may delete the references in the table mentioned in the error message:

DELETE FROM dbo.VPX_COMPUTE_RESOURCE_DAS_VM WHERE COMP_RES_ID = 123

After that you can delete the cluster object in the vSphere Client normally 🙂

Filed under: Linux, Tech, Windows No Comments
17Jan/144

DFS quota Management the easy way

This week I migrated some older Windows 2003 DFS servers to newer machines running Windows 2008R2. Just DO NOT ask me why I'm not using 2012 or 2012R2, thanks!

In the past we have been using the old style NTFS volume quotas to stop our users from storing every bullsh*t on the servers. They needed to request another 5GB whenever they ran out of disk space.
When one user's quota value changed it has to be modified on each DFS server - stupid work! And if you do not keep the values in sync, DFS will have massive problems when the user runs out of disk space on just ONE of the DFS servers...
At first we tried to solve this problem with FSRM (which also offers a full-featured command line interface), but it's not possible. FSRM can not assign individual user quotas. Thank you Microsoft!

Volume based NTFS quotas can be viewed by a command line tool, but exporting/importing or changing values (like in the GUI) is not possible via command line 🙁

This is the point where we built two different VBS-Scripts. One script is running on our master DFS server, which exports all quota settings to a CSV-File. This file is stored on the DFS volume and gets replicated to every branch DFS server. The branch DFS servers are running a script which is importing the quota settings. We are running these scripts every 10 minutes using the task scheduler.
We also placed the VBS-scripts in the same folder as the CSV file (QUOTA_FILE) so we didn't need to copy them on each single server.

Our monitoring is checking the result code of the scheduled tasks and the age of the CSV file on the master server. If this file is older than 15 minutes, there is a problem.

As a result you just have to modify a quota on the master server and it gets updated on the branch servers automatically 🙂

UPDATE: There seems to be a problem with objFSO.OpenTextFile and DFS, as DFS-R sometimes misses the changed contents of the .csv file. Just add a line (see below) to delete the csv file before writing into it.

quota_export.vbs

Const QUOTA_FILE="D:\DFSroot\_quota\usrquota.csv";
Const QUOTA_PATH="D:\";

Set objDiskQuotas = CreateObject("Microsoft.DiskQuota.1")
Set objFSO = CreateObject("Scripting.FileSystemObject")

objDiskQuotas.Initialize QUOTA_PATH, False

objFSO.DeleteFile(QUOTA_FILE)

Set objFile = objFSO.OpenTextFile(QUOTA_FILE, 2, True)
For Each objUser in objDiskQuotas
 If objUser.AccountStatus<>5 Then
 strOutput = objUser.LogonName & ";" & objUser.AccountStatus & ";" & objUser.QuotaLimit & ";" & objUser.QuotaThreshold
 objFile.WriteLine strOutput
 End If
Next

objFile.Close

quota_import.vbs

Const QUOTA_FILE="D:\DFSroot\_quota\usrquota.csv"
Const QUOTA_PATH="D:\"

Set objDiskQuotas = CreateObject("Microsoft.DiskQuota.1")
Set objFSO = CreateObject("Scripting.FileSystemObject")

objDiskQuotas.Initialize QUOTA_PATH, True
objDiskQuotas.UserNameResolution=1

Set objFile = objFSO.OpenTextFile(QUOTA_FILE, 1)

Do While Not objFile.AtEndOfStream
 quotaentries = objFile.ReadAll()
Loop
quotaentries = Split(quotaentries, vbCrLf)

For Each quotaentry in quotaentries
 if quotaentry <> "" Then
 entry = Split(quotaentry, ";")
 sLogonName = trim(entry(0))
 sQuotaLimit = int(entry(2))
 sQuotaThreshold = int(entry(3))
 Set objQuotaUser = objDiskQuotas.AddUser(sLogonName)
 If objQuotaUser.QuotaLimit<>sQuotaLimit or objQuotaUser.QuotaThreshold <> sQuotaThreshold Then
 objQuotaUser.QuotaLimit = sQuotaLimit
 objQuotaUser.QuotaThreshold = sQuotaThreshold
 End If
 End If
Next

objFile.Close
Filed under: Windows 4 Comments
17Oct/131

RunAs with elevation and encrypted credentials

As most of you know Windows UAC can be a real pain in the a**.

My problem: We use software where an additional tool is included to switch the license type (network vs. standalone). This tool saves it's settings to the HKLM registry hive and our users do not have admin privileges so we need to think about a solution. We need to run just this tool with local administrative privileges, but without asking the user for any credentials.

I tried a lot, PsExec, Elevate.exe, RunAs, but none of the solutions offered the possibility to pass (encrypted) credentials AND force the application to run with elevation.

In the end I ended in writing a VBS-Script which uses lsrunase and calls itself twice, sounds complicated but works. You need to follow these instructions:

    1. Create a unprivileged service account in your active directory and choose a secure password (you'll need it later). Just be sure to set "user cannot change password" and "password never expires".
    2. Set up your group policy that this service user gets local administrative privileges on your client computers.
    3. Search for lsrunase.zip (lsrunase.exe and lsencrypt.exe are free tools provided by Geert Moernaut which are now included in a commercial software named Lansweeper in a newer version. But the older version of these tools can be found easily.)
    4. Start lsencrypt.exe (which has a GUI) and encrypt your service user password
    5. Edit the localadmin.vbs file - pay attention to the comments
    6. Drag-and-drop the localadmin.vbs to encoder.vbs which creates an encoded localadmin.vbe file which you can copy to your clients. Be sure to put lsrunase.exe in the same directory as the .vbe script.

'------------------------------------------------------------------------------
' localadmin.vbs
'
' (by) Ing. Florian Stichlberger 2013
' http://www.stichl.at/
'
'
' Run any program with elevation and local administrative rights
' using an encrypted password
'
' WARNINGS:
' * Be sure to deploy a encoded .vbe file only - otherwise the user can be able
' to modify this script and run any command with admin privileges!
'
' * This script has been tested on Win7 Enterprise 64bit and Win8 Enterprise 64bit only
'
' * If you find any errors or improvements, please let me know...
'
' * As usual, if you decide to execute this script the author cannot be held
' responsible for any malfunctions, data corruption or unintended functionality
'------------------------------------------------------------------------------

'------------------------------------------------------------------------------
' CHANGE THE FOLLOWING PARAMETERS TO YOUR OWN VALUES
'------------------------------------------------------------------------------
Const strDomain="CONTOSO"
Const strUser="svclocaladmin"
Const strPasswd="+ld/m/4L+Lrag6irTt1AgGE="

Const strCommand="c:\some\path\name\program.exe"

'------------------------------------------------------------------------------
' DO NOT EDIT ANYTHING BELOW THIS LINE!
'------------------------------------------------------------------------------
Set oShellApp = CreateObject("Shell.Application")
Set oWshShell = CreateObject( "WScript.Shell" )
Set oFso = CreateObject("Scripting.FileSystemObject")
strCurDir = oFso.GetParentFolderName(WScript.ScriptFullName)
'shortpath is needed because lsrunase does not support double escaping of quotation marks
strScriptName = oFso.GetFile(WScript.ScriptFullName).ShortPath

' I know, Arguments.Count is not very nice but it's fast and easy
If WScript.Arguments.Count=0 Then 'running for the first time - run myself with correct credentials
 strParam = "/user:" & strUser & _
 " /password:" & strPasswd & _
 " /domain:" & strDomain & _
 " /command:""wscript " & strScriptName & " //b proceed"" /runpath:C:\"
 Call oShellApp.ShellExecute(strCurDir & "\lsrunase.exe", strParam, "", "", 1)
Else 'running the second time with (hopefully) correct credentials
 If Not IsElevated Then
 ' We do not have elevation yet, so re-execute with elevation
 Call oShellApp.ShellExecute("wscript.exe", strScriptName & " //b proceed", "", "runas", 0)
 Else
 ' In this section the command gets executed
 Call oShellApp.ShellExecute(strCommand, "", "", "", 1)
 End If
End If

Function IsElevated
 Set shell = CreateObject("WScript.Shell")
 Set whoami = shell.Exec("whoami /groups")
 strWhoamiOutput = whoami.StdOut.ReadAll()

 If InStr(1, strWhoamiOutput, "S-1-16-12288", vbTextCompare) Then
 isElevated = True
 Else
 isElevated = False
 End If
End Function

Download sources here: localadmin.zip

Filed under: Windows 1 Comment
19Jul/132

Group Policy Preferences to create a VPN connection

Everybody knows the Group Policy Preferences method to create a VPN connection on a Windows 7 client.
But there seems no way to disable IPv6 or check the "Use default gateway on remote network" checkbox via Group Policy.

Indeed, there is a hidden way:

If you look on the client, there is a rasphone.pbk file located in %appdata%\Microsoft\Network\Connections\Pbk
For system-wide connections the path is %programdata%\Microsoft\Network\Connections\Pbk

You can try to open that file using your favourite text editor - you will see a INI-style structure.

That gives us the possibility to set the missing options using Group Policy INI Preferences:

ExcludedProtocols=8 disables IPv6
IpPrioritizeRemote=1 enables that default gateway checkbox

INI preferences

Filed under: Windows 2 Comments
11Apr/132

Extracting VMware Tools drivers

Hi there,

Today I needed to extract VMware Tools drivers for use in our software deployment project.

Whenever you aleady have an .iso file (grabbing it from your next ESX host or downloading from: VMware Tools Repository) the extraction process is simple and straight-forward:

1. Unpack your .iso file using 7-zip to C:\TEMP

2. Extract the .exe on a DOS commandline:

C:\TEMP> setup64.exe /a /p c:\temp

3. When the Tools-Installer-GUI asks for the destination - just enter c:\temp again.

4 .You will find the drivers in C:\temp\Program Files\VMware\VMware Tools\VMware\Drivers

With the VMware player drivers it's a little more tricky:

1. First find your player version here: http://softwareupdate.vmware.com/cds/vmw-desktop/player/
     For Player 5.0.1 it's: http://softwareupdate.vmware.com/cds/vmw-desktop/player/5.0.1/894247/windows/packages/tools-windows-9.2.2.exe.tar

2. Download and untar the File to C:\TEMP

3. Extract the containing MSI file like this (Note: you have to create another subfolder, because extracting to the same directory fails...)

C:\TEMP> mkdir extract
C:\TEMP> tools-windows-9.2.2.exe /a /p c:\temp\extract

4. Navigate to C:\temp\extract and extract tools-windows.msi using 7-zip by right-clicking it and choosing 7-zip>extract here

5. Now we have our .iso file which you can process as described above.

So VMware is publishing a .tar file which contains a .exe which contains a .msi which contains a .iso which contains a .exe which contains our drivers. THIS IS WEIRD!

Filed under: Windows 2 Comments
17Jan/132

Why does SQL DBCC use only one CPU core

EDIT: The author of the previously linked article sent me a comment to either remove the quotation or my entire post. I just intended to share this important information by linking to the original article. Now I removed the quotation and the link - so please enjoy my own explanation for this issue 😉

Found "somewhere" on the internet: In SQL Standard Edition CHECKDB just uses one CPU core as it's doing the checks single-threaded. If you use SQL Enterprise Edition, CHECKDB is behaving like configured by the maximum degree of parallelism setting in the instance.

If you are interested in the original article you can find it on the internet by yourself

Filed under: Windows 2 Comments
8Nov/121

Port 80 in use on Windows Server 2008 R2

Today I tried to install nginx on Windows Server 2008 R2 being currently used as DC and print server.

nginx told me that there is another process which is using port 80 - strange...

If you try netstat -abn | more you will not get a process name.

TCP 0.0.0.0:80 0.0.0.0:0 LISTENING
Can not obtain ownership information

A netstat -aon | find "TCP" | find ":80" showed me Process ID 4 which means SYSTEM. wtf?

Next try:

Device Manager --> Menu View --> Show hidden Devices

Open Non-Plug and Play Drivers, select HTTP and open the properties.
If you try to stop the driver you will be shown a list of other services depending on HTTP which would also be stopped - not good...

After some googling I found the solution:

netsh http add iplisten ipaddress=::

This works instantly and I did not recognize any side effects yet.

Filed under: Windows 1 Comment
5Nov/125

Quick DFSR-Backlog-Count with VBScript

A Quick and dirty VB-Script to check the DFS Backlog (for Windows Server 2008 R2 - does NOT work on 2003 because of missing WMI-Tables...)

strComputer = "localhost"
bConnectForeign = False

    Set oWMIService = GetObject("winmgmts:\\" & strComputer & "\root\MicrosoftDFS")
    Set colRGroups = oWMIService.ExecQuery("SELECT * FROM DfsrReplicationGroupConfig")
    For Each oGroup in colRGroups
        wscript.echo "Replication Group: " & oGroup.ReplicationGroupName
        Set colRGFolders = oWMIService.ExecQuery("SELECT * FROM DfsrReplicatedFolderConfig WHERE ReplicationGroupGUID='" & oGroup.ReplicationGroupGUID & "'")
        For Each oFolder in colRGFolders
            wscript.echo "  Folder: " & oFolder.ReplicatedFolderName
            Set colRGConnections = oWMIService.ExecQuery("SELECT * FROM DfsrConnectionConfig WHERE ReplicationGroupGUID='" & oGroup.ReplicationGroupGUID & "'")
            For Each oConnection in colRGConnections
                If oConnection.Enabled = True Then
                    If oConnection.Inbound = True Then
                        if bConnectForeign then
                            numBackLog = getBackLogCount(oConnection.PartnerName, oConnection.ConnectionGUID)
                        else
                            numBackLog = getBackLogCount(strComputer, oConnection.ConnectionGUID)
                        end if
                        Wscript.echo "    " & strComputer & " <-- " & oConnection.PartnerName & " :: " & numBackLog                     Else                         numBackLog = getBackLogCount(strComputer, oConnection.ConnectionGUID)                         Wscript.echo "    " & strComputer & " --> " & oConnection.PartnerName & " :: " & numBackLog
                    End If
                End If
            Next
        Next
    Next

Function getBackLogCount(strComputer, ConnectionGUID)
    Set oWMIService = GetObject("winmgmts:\\" & strComputer & "\root\MicrosoftDFS")
    Set oDfsIUI = oWMIService.ExecQuery("SELECT * FROM DfsrIdUpdateInfo WHERE ConnectionGuid = '" & ConnectionGUID & "'")
    numBacklog=0
    for each eDfsIUI in oDfsIUI
        numBackLog=numBackLog+1
    next
    getBackLogCount = numBackLog
End Function

Result:

Group: Replication1
  Folder: Folder1
    SERVER1 --> SERVER2 :: 1
    SERVER1 --> SERVER3 :: 2
    SERVER1 --> SERVER4 :: 2

Version for OMD checks:

Set wshShell = WScript.CreateObject( "WScript.Shell" )
strComputer = wshShell.ExpandEnvironmentStrings( "%COMPUTERNAME%" )

bConnectForeign = False
Wscript.echo("<<<dfs_backlog:sep(59)>>>")

    Set oWMIService = GetObject("winmgmts:\\" & strComputer & "\root\MicrosoftDFS")
    Set colRGroups = oWMIService.ExecQuery("SELECT * FROM DfsrReplicationGroupConfig")
    For Each oGroup in colRGroups
        'wscript.echo "Replication Group: " & oGroup.ReplicationGroupName
        Set colRGFolders = oWMIService.ExecQuery("SELECT * FROM DfsrReplicatedFolderConfig WHERE ReplicationGroupGUID='" & oGroup.ReplicationGroupGUID & "'")
        For Each oFolder in colRGFolders
            'wscript.echo "  Folder: " & oFolder.ReplicatedFolderName
            Set colRGConnections = oWMIService.ExecQuery("SELECT * FROM DfsrConnectionConfig WHERE ReplicationGroupGUID='" & oGroup.ReplicationGroupGUID & "'")
            For Each oConnection in colRGConnections
                If oConnection.Enabled = True Then
                    If oConnection.Inbound = True Then
                        if bConnectForeign then
                            numBackLog = getBackLogCount(oConnection.PartnerName, oConnection.ConnectionGUID)
                        else
                            numBackLog = getBackLogCount(strComputer, oConnection.ConnectionGUID)
                        end if
                        Wscript.echo oFolder.ReplicatedFolderName & " ( from " & oConnection.PartnerName & ");" & numBackLog
                    Else
                        numBackLog = getBackLogCount(strComputer, oConnection.ConnectionGUID)
                        Wscript.echo oFolder.ReplicatedFolderName & " ( to " & oConnection.PartnerName & ");" & numBackLog
                    End If
                End If
            Next
        Next
    Next

Function getBackLogCount(strComputer, ConnectionGUID)
    Set oWMIService = GetObject("winmgmts:\\" & strComputer & "\root\MicrosoftDFS")
    Set oDfsIUI = oWMIService.ExecQuery("SELECT * FROM DfsrIdUpdateInfo WHERE ConnectionGuid = '" & ConnectionGUID & "'")
    numBacklog=0
    for each eDfsIUI in oDfsIUI
        numBackLog=numBackLog+1
    next
    getBackLogCount = numBackLog
End Function

OMD check_mk plugin:

dfs_backlog_default_values = (5,10)

# the inventory function
def inventory_dfs_backlog(info):
   inventory = []
   for line in info:
      inventory.append( (line[0], "dfs_backlog_default_values") )

   return inventory

# the check function
def check_dfs_backlog(item, params, info):
   warn, crit = params
   for line in info:
     if line[0] == item:
       backlog = int(line[1])
       perfdata = [ ( "count", backlog, warn, crit ) ]
       if backlog > crit:
         return(2,"CRIT - Backlog count: "+line[1],perfdata)
       elif backlog > warn:
         return(1,"WARN - Backlog count: "+line[1],perfdata)
       else:
         return (0,"OK - Backlog count: "+line[1],perfdata)
   return (3, "UNKNOWN - agent output error")

# declare the check to Check_MK
check_info['dfs_backlog'] = {
    "check_function"          : check_dfs_backlog,
    "inventory_function"      : inventory_dfs_backlog,
    "service_description"     : "DFS Backlog:",
    "has_perfdata"            : True,
}

Looks like:
backlog-check_mk

Filed under: Windows 5 Comments