Switching Sound Output between Headset and Speakers

How do you change the sound device a particular application is using for its audio output? I never bothered to think about this question, until the times of the shared home office.

True, in Windows you can change the default sound device, and an application that is started afterwards will use that device. But changing the sound device for a running application? It seems there is no built-in way to do that.

For Windows 7 and higher, I found the SoundSwitch applet (GitHub), which does just that. Located in the notification area, it lets you select the sound device the current application outputs its audio to. Simply click on its icon and select the device, or press a customizable hotkey.

For Ubuntu, I found Sound Switcher Indicator (GitHub, Blog). Upon installation, it can be accessed from the indicator area, and allows the selection of audio input and output devices.

Problems solved 😉

Epilogue

During preparation of this post, I tried to figure out how SoundSwitch actually switches the audio device.

It turns out that it uses the function call SetPersistedDefaultAudioEndpoint() which is also used by an application called EarTrumpet (GitHub) that tags itself as “Volume control for Windows”, but also seems to allow switching audio devices.

A review of this application by Scott Hanselman indicates that the method and its interface are not officially documented:

Internal Audio Interface: IAudioPolicyConfigFactory

Gets them access to new APIs (GetPersistedDefaultAudioEndpoint / SetPersistedDefaultAudioEndpoint) in RS4 that let’s them ‘redirect’ apps to different playback devices. Same API used in modern sound settings.

Code here with no public API yet?

Sending Email Notifications for Windows Updates

I have this Windows server installed which hosts a couple of websites, and is really not doing much.

Every now and then I need to log in for some server operation, only to find the typical Windows Updates Pending notification. Every time this happens I think to myself, hey, I’d like to get some notification that there are updates available, without having to log in.

So I finally dug around the internets – well, as it turned out, the info was all on StackOverflow:

The result is a tiny PowerShell script called update-mailer.ps1, which queries the Windows Update Service and sends an email accordingly, and can be found on my GitHub PowerShell repository.

To run this script as a Scheduled Task, create a .cmd batch file containing the command

powershell.exe -ExecutionPolicy Bypass -File path\to\update-mailer.ps1

to bypass PowerShell’s restricted execution policy, and call the script from the task.

Updating TortoiseGit to use github’s Personal Access Token

I recently got github’s email on their changes to authentication tokens, but of course ignored as long as I could.

We recently updated the format of our API authentication tokens, providing additional security benefits to all our customers.

So today was the day to update my local authentication token in TortoiseGit.

I headed over to github’s Personal Access Token page to generate a new token.

But it was not really clear how to add it as authentication for repositories existing on my local PC.

After some google-fu, I opened the TortoiseGit Settings dialog in the root directory of one of my repositories,

TortoiseGit credentials (right-click on repository directory)

changed the Credential helper to Advanced, and entered my github username.

The next TortoiseGit/Push… command open an authentication dialog where I copied the github token in the password field.

After the push was completed, I could verify that the new token was added in Windows under Control Panel / Accounts / Credential Manager / Windows Credentials

Updated Windows credentials

Use awk to grep

I have gawk installed on my Windows 10 machine, but no grep, but still needed to quickly find text in some files.

So I came up with (read: “found on the internet”) this one-liner

@for /f "eol=: delims=" %F in ('dir /b /s [directory]') do
@awk "/[search string]/ {print $0}" %F

Usually I use grepWin for such tasks, but only later realized that a simply Ctrl-C would copy the selected search result to the clipboard – grepWin’s context menu does not have a menu item for this function, even though it has been suggested in a related issue.

I also noticed grepWin has a memory problem if you search huge files on a machine with little RAM. On the other hand, it searches using the Windows codepage rather than the DOS codepage.

Which version of SQL Server and SSMS can be installed on which Windows version?

As my Windows installation ages, it collects various versions of development tools, such as SQL Server, SQL Server Management Studio (SSMS), or Visual Studio.

But for every version of Windows the question is: will the next version of product X be installable on Windows Y?

So here is the answer for SQL Server and SSMS on Windows versions 7 (32-bit), 8.1 (64-bit) and 10 (64-bit)

SQL/SSMS Version Win7-32 Win8.1-64 Win10-64
2008 10 Y ? ?
2012 11 Y Y Y
2014 12 Y Y Y
SSMS 2016 13 Y Y Y
SQL 2016 13 Y Y
SSMS 17 17 Y Y
SQL 2017 14 Y Y
SSMS 18 18 Y Y
SQL 2019 15 Y

 

Solving Error 0x80092004 for Security Update KB4516655

Granting my Windows installations one last round of updates, I noticed that Windows Update would not let me install KB4516655.

Hopping around through the internets forums to figure out how to solve the situation, I found that the security update needed another update which is probably not on the list of dependencies of the update package:

KB4474419 had already been installed

KB4490628 this one was missing (and once linked correctly, and once linked to a different KB 4512506 here, which I did not immediately recognize)

KB4512506 (Monthly Rollup August 2019)

After applying those updates manually, KB4516655 could be installed, allowing the succeding rollups 2019-09 and 2019-12.

Of course, the WindowsUpdate.log file does not indicate, WHY things go wrong:

Misc =========== Logging initialized (build: 7.6.7601.24085, tz: +0100) ===========
Misc = Process: C:\Windows\system32\wuauclt.exe
Misc = Module: C:\Windows\system32\wuaueng.dll
Handler :::::::::::::
Handler :: START :: Handler: CBS Install
Handler :::::::::
Handler Starting install of CBS update 7CC120FB-9672-4AE5-BBA6-90651174A717
Handler CBS package identity: Package_for_KB4516655~31bf3856ad364e35~amd64~~6.1.1.1
Handler Installing self-contained with source=C:\Windows\SoftwareDistribution\Download\4009abf0458aef77b1e27406d1395603\Windows6.1-KB4516655-x64.cab, workingdir=C:\Windows\SoftwareDistribution\Download\4009abf0458aef77b1e27406d1395603\inst
Report REPORT EVENT: {0478CEF6-1B68-4959-A8F2-5DD5AD90DAFA} 2020-01-11 11:23:25:458+0100 1 181 101 {271A1B3A-DD7A-4D8A-94E1-9E44BFC9149F} 501 0 wusa Success Content Install Installation Started: Windows successfully started the following update: Sicherheitsupdate für Windows (KB4516655)
Handler FATAL: CBS called Error with 0x80092004, 
Handler FATAL: Completed install of CBS update with type=0, requiresReboot=0, installerError=1, hr=0x80092004
Handler :::::::::
Handler :: END :: Handler: CBS Install
Handler :::::::::::::

And the Windows Update “Help” is just as unhelpful.

Installing Terratec S7 on 64-bit Windows 8.1

I got myself a Terratec S7 because my existing Cynergy S2 card started to show problems, and the situation is not resolved yet, mainly because the S7 does not appear to control the dish as it should in the PC I want it to run.

To figure out where exactly the problem is, I took the S7 and tried to install everything on a separate laptop, not contaminated by previous installations of any TV software 😉

I got the latest drivers for Windows 8.1, and of course DVBViewer, which superseded Terratec Home Cinema, well-known from the S2 installation.

I installed the drivers, but did not immediately notice that the installation had failed. Only when DVBViewer presented an empty list of supported hardware, and after installing the drivers again, I realized the failure (there is no visual clue as to whether installation was successful or not, you actually have to *read* *text* 😉 ).

The output of the Windows Error Report (accessible from the error entry in the Event Log) listed an error code E0000247

Version=1
EventType=PnPDriverImportError
EventTime=131400033808805347
Consent=1
ReportIdentifier=b04db504-3f95-11e7-8257-441ca8536b2a
Response.type=4
Sig[0].Name=Architektur
Sig[0].Value=x64
Sig[1].Name=Win32-Fehler
Sig[1].Value=E0000247
Sig[2].Name=INF-Name
Sig[2].Value=terratec_s7.inf
Sig[3].Name=Treiberpakethash
Sig[3].Value=b47a89cb47c6613e055bc51ffc8935d320b543dd
DynamicSig[1].Name=Betriebsystemversion
DynamicSig[1].Value=6.3.9600.2.0.0.256.48
DynamicSig[2].Name=Gebietsschema-ID
DynamicSig[2].Value=3079
FriendlyEventName=Die Treibersoftware konnte nicht installiert werden.

which hints at a certificate validation error (hint, hint).

The Device Install Log at C:\Windows\Inf\setupapi.dev.log was also rather clear on the issue:

sig: {_VERIFY_FILE_SIGNATURE} 10:56:13.520
sig: Key = terratec_s7.inf
sig: FilePath = g:\terratec s7\terratec_s7_rev.4_driver_1.0.0828.0_xp_vista_7_8\terratec s7 rev.4\bda driver 1.0.0828.0\64bit\terratec_s7.inf
sig: Catalog = g:\terratec s7\terratec_s7_rev.4_driver_1.0.0828.0_xp_vista_7_8\terratec s7 rev.4\bda driver 1.0.0828.0\64bit\terratec_s7.cat
! sig: Verifying file against specific (valid) catalog failed! (0x800b0109)
! sig: Error 0x800b0109: A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.
sig: {_VERIFY_FILE_SIGNATURE exit(0x800b0109)} 10:56:13.567
sig: {_VERIFY_FILE_SIGNATURE} 10:56:13.571
sig: Key = terratec_s7.inf
sig: FilePath = g:\terratec s7\terratec_s7_rev.4_driver_1.0.0828.0_xp_vista_7_8\terratec s7 rev.4\bda driver 1.0.0828.0\64bit\terratec_s7.inf
sig: Catalog = g:\terratec s7\terratec_s7_rev.4_driver_1.0.0828.0_xp_vista_7_8\terratec s7 rev.4\bda driver 1.0.0828.0\64bit\terratec_s7.cat
! sig: Verifying file against specific Authenticode(tm) catalog failed! (0x800b0101)
! sig: Error 0x800b0101: A required certificate is not within its validity period when verifying against the current system clock or the timestamp in the signed file.
sig: {_VERIFY_FILE_SIGNATURE exit(0x800b0101)} 10:56:13.598

Since 64-bit Windows requires device drivers to be signed, this seemed to be a show stopper. However, you can disable signature verification by typing (in admin mode)

bcdedit /set testsigning on

which fortunately worked on my laptop.

After reboot, I was able to install the drivers, and Windows even is so nice as to warn you if you install unsigned drivers

terratec signed driver

(There is probably an alternative method by extracting certificates from the installer’s .cat files, but I didn’t have to try, so I can’t tell.)

Starting up DVBViewer again, it immediately recognized the S7, and a range scan found several hundred channels fine. I switched to a couple of channels that I also had on my TV, but there was no picture.

Forum talk mentions this issue, along with LAV filters, which I had come across earlier clicking through the files of the Home Cinema download page. So I downloaded TERRATEC_Home_Cinema_Codec_Patch.exe from there, installed it, and finally got a TV on my laptop.

 

Adding SSL Wildcard Certificates to IIS Webs

As web browsers start to issue warnings on plain http websites if you are asked to input username/password, it’s time to add SSL certificates even on dev/test servers. We can expect more aggressive warnings in the future 😉

Apparently there is a way to create a self-signed certificate built into IIS (screenshot from Windows Server 2008)

iis create certificate

but this seems to create cerficates only for the host name, not for any domain hosted on the machine.

Back to square one, start up a current Linux machine, and make sure your openssl is newer than version 1.0.1f. (Remember Heartbeed?).

The instructions I found to create self-signed certificates are nearly identical (source, source, source)

openssl genrsa 2048 > my-host.key
openssl req -new -x509 -nodes -sha1 -days 3650 -key my-host.key > my-host.cert
# make sure Common Name starts with "*.", e.g. *.my-host.com
openssl x509 -noout -fingerprint -text < my-host.cert > my-host.info
cat my-host.cert my-host.key > my-host.pem

For use in IIS, you need to create a .pfx from these certificate files:

openssl pkcs12 -inkey my-host.pem -in my-host.cert -export -out my-host.pfx

Copy the .pfx to your IIS machine.

In IIS Manager, select “Server Certificates” on the server node, click “Import…” to import the .pfx certificate.

Start up mmc, “File”, “Add/Remove Snap-in”, select “Certificates”, “Add”, “Computer account”, “Finish”, “OK”, (this click orgy shows you how important certificates were in 2008, as compared to Start/Administrative Tools/Data Sources (ODBC) 😉 ) and find the imported certificate(s) under

Console Root\Certificates\Personal\Certificates

Right-click each of them, select Properties, and make sure that the Friendly Name starts with “*.” for wild-card certificates. Otherwise, you cannot assign a host name for https web sites.

Back in IIS Manager, select each site you want to add https support, click Bindings, Add, select Type: https and select the wild-card SSL certificate. Only if the friendly name starts with *, you can/must set the site’s Host name. Click OK and you are done.

If you want your sites to redirect http to https automatically, make sure the Require SSL box is not checked in the site’s SSL Settings.

The minimal web.config to perform these redirects looks like this (source, source)

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Redirect-HTTP-HTTPS-IIS">
          <match url="(.*)" />
          <conditions>
            <add input="{HTTPS}" pattern="^OFF$" ignoreCase="true" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" 
            redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

Be aware that while these steps enable https for your IIS sites, self-signed certificates still require the users to explicitly accept the certificates in their browsers, which will raise an “Unknown issuer” warning at their first visit.

Update: There also seems to be a Powershell way to do it 😉

Installing AWStats on Windows Server 2012

To install AWStats on Windows, first download the current version from awstats.org. If you don’t have Perl on your machine, get Strawberry Perl for Windows, as ActivePerl requires an annual Business License for production use.

On the server, create a web directory and a data directory for awstats. Follow the steps in the AWStats Setup Guide.

To access the log files of a remote IIS, I created a read-only share on c:\inetpub\LogFiles, and had to run

icacls c:\inetpub\LogFiles /reset /t

to allow non-admin access to the IIS log files.

To get Strawberry Perl to run on IIS, follow this Installation Guide:

  • In the Web Server role, you need to have the CGI feature installed.
  • In IIS Administrator, create a web site or application hosting AWStats. In the site or application, you need to add a Script Map for *.pl executing
C:\path\to\perl.exe "%s" %s

Things should be running by now if you browse to

http://myHost/awstats/cgi-bin/awstats.pl?config=mySite

I noticed that the stats only included data from the installation date (IIS logs are configured to daily log files).

Answers on the internetz suggest to merge old log files using logresolvemerg.pl, a script that ships with awstats.

C:\awstats\tools>perl logresolvemerge.pl [all my log files] > merged.log

Replace the LogFile entry in your config file(s) to point to the merged log file

LogFile="C:\awstats-data\merged.log"
#LogFile="\\path\to\LogFiles\W3SVC1\u_ex%YY-1%MM-1%DD-1.log"

and run

perl awstats.pl -config=mySite

again after deleting the previously generated data files.

Unfortunately, the merged log only resulted in “dropped” and “corrupted” records:

Phase 1 : First bypass old records, searching new record...
Searching new records from beginning of log file...
Jumped lines in file: 0
Parsed lines in file: 30376
Found 16100 dropped records,
Found 0 comments,
Found 0 blank records,
Found 14276 corrupted records,
Found 0 old records,
Found 0 new qualified records.

This may be caused by a number of reasons, but it turned out that the merged log requires a specific LogFormat:

LogFormat="%time2 %other %method %url %query %other %logname %host %ua %code %other %other %other"

Finally, I created a batch file awstats.cmd to update all my statistics

net use z: \\host\LogFiles awstats /user:awstats
d:
cd D:\wwwroot\awstats\wwwroot\cgi-bin
perl awstats.pl -update -config=mySite1
perl awstats.pl -update -config=mySite2
...
net use z: /delete

and created a scheduled task to automatically execute the script every day.