Upgrading Windows 10 from 10041 to 10049 issues

I’ve been running a copy of Windows 10 (build 10041) in a VirtualBox VM and had major problems trying to update it to build 10049 (yes on the fast track). Other than the fact that the update/install takes extremely long it also seems to get stuck at 30% – after having being running for more than 24 hours already! I tried multiple times and each time it got stuck at the same time.

So I ventured out on that thing the Internet and found possible related posts of other people having similar issues (on VMWare or even physical installs) – all complaining about the 30% mark where things get stuck. One suggestion caught my eye – sorry, lost the original link to that but basically it suggests disconnecting the network (or pulling the network cable on physical install) just after the update download finished. Additionally some VMWare people suggested removing their VMWare client tools.

So I tried the same on my VirtualBox install. First I uninstalled the VirtualBox client tools. Then I started the install (download). Once the download finished (again…) I disconnected the network (unticked ‘Cable Connected’) and whoa! The install jumped to 30% almost straight away, stayed there for a minute or two (almost made me think this is all for nothing..) and then the progress bar started moving again. Another reboot around 75% and then all were done! Wow!

Well, at least now I’m ‘back’ at build 10049 waiting for the next one (10051)…

 

QuickMon 4

Just a quick post to announce the first (official) release of QuickMon 4.

There might be some minor bugs that must be ironed out but the basic product is done.

Have fun.

QuickMon 4 Beta

Heads up folks! A public Beta of QuickMon 4 has been released. Please go to QuickMon to download and play with it.

People that has not seen the Alpha yet would notice some major changes compared to version 3.x. The biggest change it that a Collector (now called Collector host) can contain multiple agents of multiple types all tested together to raise one single alert if needed. Of course you can still use it the old way with a collector host containing only a single agent type and have child collector hosts depending on it.

Another area of big change is that viewing the details of a collector’s state, stats, history, alert details and other info gathered are all placed inside a single view (window). This makes it a lot easier to see what is happening with alerts. This detail view is now also ‘Remote host’ aware so it will run and gather details from a (QuickMon 4) remote host as if it is running on ‘that’ machine.

Ok, go download it and have fun… and report back if you have issues or suggestions.

Calling Soap web service from Desktop app with Windows Authentication

I recently had to create a small proof of concept app that calls a soap web service which must be a bit more secure than just allowing Anonymous access. The Web Service requires Windows Authentication to be enabled (NTLM as main provider) with Anonymous disabled.

Calling this web service should be straight forward as you would expect a Windows (Forms) desktop application to pass any logon details when making network related calls. Unfortunately when using Web Services the call seems to be made ‘Anonymous’ by default using the generated proxy class as created by Visual Studio. Fortunately the solution is straight forward provided you can find it on Google (or any other search engine 😉 )

Without going into the real details of how and why this work here is the solution: You have to add security details to the ‘binding configuration’ of the endpoint of the Web Reference. In short the config must look something like this:

  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
       <binding name="SomeServiceSoap">
                <strong><security mode="TransportCredentialOnly">
                  <transport clientCredentialType="Ntlm" proxyCredentialType="None"
                      realm="" />
                  <message clientCredentialType="UserName" algorithmSuite="Default" />
                </security></strong>
              </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://myserver/webservices/SomeService/SomeService.asmx"
                binding="basicHttpBinding"
                bindingConfiguration="SomeServiceSoap"
                contract="SomeServiceWS.SomeServiceSoap"
                name="SomeServiceSoap" />
    </client>
  </system.serviceModel>

The important part here is the <security> tag and its content. Like explained before on the server side Only ‘Windows Authentication’ must be enabled with the ‘NTLM’ provider as the first provider.

Possibly this can also be done through code but I haven’t tried that yet.

QuickMon HTTP Activation catch

I recently created a test Windows 8 (8.1) VM to just play around and took the opportunity to test the QuickMon install as well. Usually I simply test on my own machine where I know it works already. This is of course not a major problem in itself but it means I’m not testing what will happen to the tool if you install it on a fresh/clean machine.

Surprisingly/luckily just about everything worked first time – not that I expected less (ye ye a bit arrogant I know 😉 ) and I was happy that QuickMon ‘out of the box’ is so good. However…. there is one thing that did not work as expected (ok ok it did not work at all) – The Remote host functionality built into the Windows Service.

This is actually not a QuickMon problem per se – it is a requirement of or dependency on the underlying operating system that the WCF functionality must be available. The remote host functionality of QuickMon uses HTTP Activation which is not installed by default on a new Windows 8 (or probably previous versions) installation.

The ‘fix’ is really simple – simply go to ‘Control Panel’ -> ‘Turn Windows features on or off’ -> .Net Framework 4.5 Advanced Services (or 4.0 if present) -> WCF Services -> check HTTP Activation on. Then do a reboot even though Windows doesn’t ask for it after the install – somehow the functionality does not really work right away. It should then be working provided you checked all the other know issues – like firewalls and stuff.

I’ll see if I can build in some check into the service itself to generate an error (Event log or something) to high-light if this feature is not available on the operating system where it needs to run.

One more thing to add to QuickMon… hehe

How to access the ‘Service Controller Database’ remotely on a Workgoup network

After having some issues with my home computers not being able to ‘see’ each others services I started digging around for solutions – having already checked all the other possible problems. The main issue is that all these computers are running on an old fashioned ‘Workgroup’ since I don’t have an Active Directory Controller (no Windows Servers). Thus all the machines connect using the same username/password combination.

I’ve made sure of things like firewalls, user accounts (as mentioned already), UAC etc. are all ok but still I got the ‘Cannot open Service Control Manager Database’ error (Access denied (5)). I started suspecting there must be another level of security that is blocking access to view/start/stop Windows services across different machines. Then I stumbled across articles describing ACLs and the issue that to this day Microsoft has not exposed Service ACL’s through .Net yet (yet they have things like File and Registry ACLs exposed through System.Security namespace…).

The only way to get to these ACL’s are through old fashioned Win32 APIs or using the SC.exe utility. I’ve read that someone wrote a C# wrapper class for these somewhere but I could not find any remaining source of this through Google. Bummer… Then using the SC.exe utility through some nasty loosely coupled integration is the only solution…

To view the current DACL (Discretionary Access Control List) for ‘Service Controll Manager’ you can use the followig command on the source/host computer you want to connect to:

sc sdshow scmanager

That should give you something like this:

D:(A;;CC;;;AU)(A;;CCLCRPRC;;;IU)(A;;CCLCRPRC;;;SU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;BA)S:(AU;FA;KA;;;WD)(AU;OIIOFA;GA;;;WD)

Now, the part that was relevant to me using a ‘Workgroup’ network is the (…AU) part because for some reason even though I’m using the same user account/Password on all machines – and this account is an Administrator on each machine, the system only recognize the user as part of the Authenticated users group ONLY. Thus the  (A;;CC;;;AU) part is not sufficient to allow access to the service control manager database…

To get access to the Service Controller Database you need permissions like this: (A;;CCLCRPRC;;;AU)

To understand what all those letters use please refer to ‘Best practices and guidance for writers of service discretionary access control lists‘ which explains the whole lot. The following command can be used to ‘fix’ the access to the ‘Service Controller Database’: (note that is is just an example!! Check the output of the previous command first)

 sc.exe sdset scmanager D:(A;;CCLCRPRC;;;AU)(A;;CCLCRPRC;;;IU)(A;;CCLCRPRC;;;SU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;BA)S:(AU;FA;KA;;;WD)(AU;OIIOFA;GA;;;WD)

After running this you should be able to access the  ‘Service Controller Database’ remotely (assuming all the other things have been checked). All good and wonderful! uhmm… Then I discover this does not display all services… bugger again..

Actually there are two parts to the original problem – as I discovered that each Windows service on its own has an ACL that can/should be set. Some ‘system’ services already come with permissions for AU (Authenticated Users) so they are visible by default. Most other and particularly my custom created services don’t have the right ACLs set. To fix that is simple… Just repeat the process above for that particular service – like this (for my QuickMon 3 Service):

Sc sdshow "Quickmon 3 service"

This should give an output like this:

D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)

As you can see it does not have any permissions for AU. To fix access to that server you simply have to add the AU permissions like this:

sc.exe sdset "Quickmon 3 service" D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)

Now of course you have to repeat this for each Windows Service you need access to…

To help in this process I created the following PowerShell script that list all Windows Servers plus their ACLs:

$services = @{}
Get-Service | foreach {
    $DACL = sc.exe sdshow $_.ServiceName
    $service = @{
        'ServiceName' = $_.ServiceName
        'DisplayName' = $_.DisplayName
        'ServiceType' = [string]$_.ServiceType
        'DependsOn'   = [string]$_.ServicesDependedOn
        'State'       = [string]$_.Status
        'DACL' = ([string]$DACL).Trim()
    }
    $serviceObj = New-Object -TypeName PSObject -Property $service
    $services.Add($_.ServiceName,$serviceObj)
}
$services.Values | select ServiceName, DisplayName, ServiceType, State, DependsOn, DACL | Sort-Object ServiceName

Now you have to repeat the whole process for each service… And that is how it’s done… Enough to keep you out of mischief or perhaps enough to get you into it again…

Getting GDI object count per process in Powershell

Ever wanted to query the GDI object count in PowerShell per process?

Here’s how:

"Number of GUI handles per process"
$sig = @'
[DllImport("User32.dll")]
public static extern int GetGuiResources(IntPtr hProcess, int uiFlags);
'@

Add-Type -MemberDefinition $sig -name NativeMethods -namespace Win32

$processes = [System.Diagnostics.Process]::GetProcesses()
[int]$gdiHandleCount = 0
ForEach ($p in $processes)
{
    try{
        $gdiHandles = [Win32.NativeMethods]::GetGuiResources($p.Handle, 0)
        $gdiHandleCount += $gdiHandles
        $p.Name + " : " + $gdiHandles.ToString()   
    }
    catch {
        #"Error accessing " + $p.Name
    }
}
"Total number of GDI handles " + $gdiHandleCount.ToString()

Alternatively you can use Process Explorer from Microsoft (originally sys-internals) if it is installed.

How to build an C# Application that can relaunch itself in Admin mode – without UAC prompt

Lets start by emphasizing that this is NOT a way to create a hack. In order for this to work you (the user) needs to be an Administrator and access to be able to launch applications in ‘Admin mode’ anyway. The first time when the application needs to set up this functionality it needs to run in Admin mode as well (for which you’ll have to be prompted by UAC). Only after this and for the future the application in ‘Non-admin’ mode can then relaunch itself in ‘Admin mode’ without showing the UAC prompt.

The ‘trick’ (not hack) is to use the built-in Windows Task scheduler that can launch applications with the ‘highest’ priority setting. Take note that this also stops you from launching the app with any command line parameters – but there are other ways an application can ‘communicate’ with itself/another instance of itself e.g. by saving its own settings before launching the second instance and the second instance reading those settings again.

So how can a (C#) application integrate this easily? My first idea was to call the Task scheduler (Schtasks.exe) manually with the required parameters to create a task of launching the app again later in admin mode. The problem part is finding out if the task already exists or not. Then I came across an article that showed how the COM+ library for the Task Scheduler can be used from .Net which make it a whole lot easier to interact.

Task Scheduler COM+ library

In your application’s references add a reference to ‘TaskScheduler 1.1 Type Library’ (Interop.TaskScheduler.dll) usually located on ‘c:\Windows\SysWow64\taskschd.dll (on 64-bit at least). Then you can add the following type of code in your project:

Code

To test if task exists or is running already:


private string myLaunchTaskName = "RunMeAsAdmin";

private bool LaunchTaskExist()
{
  try
  {
    TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();
    ts.Connect(null, null, null, null);
    if (ts.Connected)
    {
      TaskScheduler.ITaskFolder root = ts.GetFolder("\\");
      TaskScheduler.IRegisteredTask task = root.GetTask(myLaunchTaskName);
      if (task != null)
        return true;
    }
  }
  catch { }
  return false;
}
private bool TaskAlreadyRunning()
{
  try
  {
    TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();
    ts.Connect(null, null, null, null);
    if (ts.Connected)
    {
      foreach (TaskScheduler.IRunningTask td in ts.GetRunningTasks(0))
      {
        if (td.Name == myLaunchTaskName)
          return true;
      }
    }
  }
  catch { }
  return false;
}

To create the task the first time:

function CreateSelfLaunchTask()
{
  try
  {
    if (AdminModeTools.IsInAdminMode()) //Different library to test if app is in Admin mode
    {
      TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();
      ts.Connect(null, null, null, null);
      if (ts.Connected)
      {
        TaskScheduler.ITaskDefinition task = ts.NewTask(0);
        task.RegistrationInfo.Author = "Me";
        task.RegistrationInfo.Description = myLaunchTaskName;
        task.Principal.RunLevel = TaskScheduler._TASK_RUNLEVEL.TASK_RUNLEVEL_HIGHEST;
        task.Settings.MultipleInstances = TaskScheduler._TASK_INSTANCES_POLICY.TASK_INSTANCES_IGNORE_NEW;
        TaskScheduler.ITimeTrigger trigger = (TaskScheduler.ITimeTrigger)task.Triggers.Create(TaskScheduler._TASK_TRIGGER_TYPE2.TASK_TRIGGER_TIME);
        trigger.Id = "NoTime";
        trigger.StartBoundary = "2000-01-01T12:00:00";
        trigger.StartBoundary = "2000-01-01T12:00:00";
        TaskScheduler.IExecAction action = (TaskScheduler.IExecAction)task.Actions.Create(TaskScheduler._TASK_ACTION_TYPE.TASK_ACTION_EXEC);
        action.Id = "Run exe";
        action.Path = System.Reflection.Assembly.GetExecutingAssembly().Location;
        action.WorkingDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

        TaskScheduler.ITaskFolder root = ts.GetFolder("\\");
        TaskScheduler.IRegisteredTask regTask = root.RegisterTaskDefinition(
          myLaunchTaskName,
          task,
          (int)TaskScheduler._TASK_CREATION.TASK_CREATE_OR_UPDATE,
          null,
          null,
          TaskScheduler._TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN);
      }
    }
    else
    {
      MessageBox.Show("To create the task you must start this program in 'Admin' mode.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
  }
  catch(Exception ex)
  {
    MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
  }
}

Then to call the task:

function void RunAppAsAdmin()
{
  try
  {
    if (LaunchTaskExist())
    {
      if (!TaskAlreadyRunning())
      {
        TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();
        ts.Connect(null, null, null, null);
        if (ts.Connected)
        {
          TaskScheduler.ITaskFolder root = ts.GetFolder("\\");
          TaskScheduler.IRegisteredTask task = root.GetTask(myLaunchTaskName);
          TaskScheduler.IRunningTask runTask = task.Run(null);
        }
      }
      else
      {
        MessageBox.Show("The task is already running!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }
    else
    {
      MessageBox.Show("The task does not exist yet!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
  }
}

If for some reason you need to delete the task you can use this:

private void DeleteRunAsAdminTask()
{
    try
    {
        if (AdminModeTools.IsInAdminMode())
        {
            if (LaunchTaskExist())
            {
                TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();
                ts.Connect(null, null, null, null);
                if (ts.Connected)
                {
                    TaskScheduler.ITaskFolder root = ts.GetFolder("\\");
                    TaskScheduler.IRegisteredTask task = root.GetTask(myLaunchTaskName);
                    if (task != null)
                    {
                        root.DeleteTask(myLaunchTaskName, 0);
                    }
                }
            }
            else
            {
                MessageBox.Show("The task does not exist!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        else
        {
            MessageBox.Show("To delete the task you must start this program in 'Admin' mode.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

With all these ‘bits’ you can build an application that can launch itself in ‘Admin’ mode. Have fun kidz but not too much!

I’ve tested this on Windows Vista, 7, 2008/R2 and 8. I don’t have access to any XP machines anymore but I doubt it will work on XP (or 2003)… duhh.. Just remembered XP and 2003 does not have ‘Admin’ mode anyway so this does not apply… silly me.

Update: I now have one of my utilities actually using this code: Service Monitor

Start or stop BizTalk Applications using PowerShell

This is not actually something new but for anyone else that wants to quickly have a reference to it, here are two PowerShell scripts to stop and start BizTalk applications.

Stopping a specified Application:

if ($args.count -eq 0) {
  "You must specify the BizTalk Application name to stop!"
}
else{
    $BTSAppName = $args[0]
    $SQLInstance = "."
    $BizTalkManagementDb ="BizTalkmgmtdb"
    [void] [System.reflection.Assembly]::LoadWithPartialName("Microsoft.BizTalk.ExplorerOM")
    $Catalog = New-Object Microsoft.BizTalk.ExplorerOM.BtsCatalogExplorer
    $Catalog.ConnectionString = "SERVER=$SQLInstance;DATABASE=$BizTalkManagementDb;Integrated Security=SSPI"

    $BTSApp = $Catalog.Applications[$BTSAppName]
    if ($BTSApp.Status -ne "stopped")
    {
        "Stopping" + $BTSApp.Name
        $BTSApp.Stop("StopAll")
        $catalog.SaveChanges()
    }
    else
    {
        $BTSApp.Name + " is already stopped"
    }
}

Starting a specified Application:

</pre>
<pre>if ($args.count -eq 0) {
  "You must specify the BizTalk Application name to start!"
}
else{
    $BTSAppName = $args[0]
    $SQLInstance = "."
    $BizTalkManagementDb ="BizTalkmgmtdb"
    [void] [System.reflection.Assembly]::LoadWithPartialName("Microsoft.BizTalk.ExplorerOM")
    $Catalog = New-Object Microsoft.BizTalk.ExplorerOM.BtsCatalogExplorer
    $Catalog.ConnectionString = "SERVER=$SQLInstance;DATABASE=$BizTalkManagementDb;Integrated Security=SSPI"

    $BTSApp = $Catalog.Applications[$BTSAppName]
    if ($BTSApp.Status -ne "started")
    {
        "Starting " + $BTSApp.Name
        $BTSApp.Start("StartAll")
        $catalog.SaveChanges()
    }
    else
    {
        $BTSApp.Name + " is already started"
    }
}

List all .Net versions using PowerShell

A quick tip (script) how to list all the .Net (major) versions of a list of machines.

$serverListFile = "<Path to file>\computers.txt";
$computers = Get-Content -path $serverListFile

$BASEDOTNETPATH = "\c$\Windows\Microsoft.NET\Framework\"

function CheckNet45($computerName){
  $NETROOTKEY = "SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4"
  $keyname = $NETROOTKEY + "\\Full"
  try{
    $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine", $computerName)
    if ($reg -ne $null){
      if ($reg.OpenSubKey($keyname).GetValue("Version").ToString().StartsWith("4.5")){
        return $True
      }
    }
  }
  catch {
    #do nothing
  }
  return $False
}

foreach($computer in $computers)
{
  $computer
  $ok = Test-Connection $computer -Count 1 -Quiet
  if ($ok) {
    $computerBasePath = "\\" + $computer + $BASEDOTNETPATH
    $versionStr = ""
    if (Test-Path ($computerBasePath + "v1.0.3705")){
      $versionStr = $versionStr + "1.0,"
    }
    if (Test-Path ($computerBasePath + "v1.1.4322")){
      $versionStr = $versionStr + "1.1,"
    }
    if (Test-Path ($computerBasePath + "v2.0.50727")){
      $versionStr = $versionStr + "2.0,"
    }
    if (Test-Path ($computerBasePath + "v3.0")){
      $versionStr = $versionStr + "3.0,"
    }
    if (Test-Path ($computerBasePath + "v3.5")){
      $versionStr = $versionStr + "3.5,"
    }
    if (Test-Path ($computerBasePath + "v4.0.30319")){
      $versionStr = $versionStr + "4.0,"

      if (CheckNet45($computer)){
        $versionStr = $versionStr + "4.5,"
      }
    }
    $versionStr = $versionStr.TrimEnd(',')
    "  Installed version(s): " + $versionStr

  }
  else{
   " Is not pingable!"
  }
}

All you have to do is create a text file with a list of machine names (one name per line). It does assume you have Admin rights so you can access the C$ share and read the remote registries.