Disable Windows User Account Control

Posted 02/27/2020 1:00 PM by Corey Klass

Adding a Windows user to the local Administrators group will not necessarily give that account full administrative access, as Microsoft also introduced an additional layer of security called "User Account Control". If you know what you're doing and want to disable it:

Open a command prompt with the "as administrator" option and run gpedit.

Navigate to: Computer Configuration -> Windows Settings -> Security Settings -> Local Policies -> Security Options

Look for User Account Control: Run all administrators in Admin Approval Mode and select "Disabled".

Restart Windows and you should have your permissions resolved.

Failure to Create SQL Server Always On Availability Group

Posted 01/13/2020 9:05 AM by Corey Klass

I am currently in the process of migrating my company's SQL Server replication strategy from Log Shipping to Always On Availability Groups. This involved the addition of several new VMs to my production SQL Cluster.

When I attempted to create the first SQL Server Availability Group, I received the following error message:

Msg 19405, Level 16, State 17, Line 3
Failed to create, join or add replica to availability group 'Primary', because node 'DB05' is a possible owner for both replica 'DB04\ReadOnly' and 'DB05\Primary'. If one replica is failover cluster instance, remove the overlapped node from its possible owners and try again.

In the Failover Cluster Manager, I had specified that DB05 is not a possible owner of Primary. However, viewing possible owners in Powershell revealed that the owner was still incorrectly set.

First you need to list the cluster resources by executing get-clusterresource to get the name of your SQL Server service:

get-clusterresource

To view the cluster resource owners, you execute get-clusterownernode for the name of your SQL Server from above:

get-clusterownernode

To set the correct cluster resource owners, you execute set-clusterownernode

set-clusterownernode

You can then view the cluster resource owners again with get-clusterownernode to verify that they are set correctly:

get-clusterownernode

The Availability Group can now be created.

Office 2019 for Mac Search Not Working

Posted 01/01/2020 4:30 PM by Corey Klass

I recently migrated to a new MacBook Pro and discovered that searching in Outlook for Mac 2019 stopped working. I tried the various solutions people have suggested on the Internet, including creating a new Outlook profile and forcing Spotlight to reindex the message database, but they were ineffective.

What ended up working in my particular instance was to completely uninstall all traces of Office from my Mac per this Microsoft Support article, reboot, and then reinstall.

Please Note: This will clear all of your preferences and delete all of your Outlook data. If you are connected to a mail server (such as Gmail, Exchange or Office 365), you will be able to re-download your mail. Any local email/contacts/calendar events will be lost. This will also delete any customized Word templates.

From the Microsoft Support article:

Remove Office Applications

  • Open Finder > Applications.
  • Command+click to select all of the Office for Mac applications.
  • Drag them to the Trash, or Ctrl+click an application you selected and click Move to Trash.

Remove files from your user Library folder

  • In Finder, press Command+Shift+G.
  • In the window that opens, enter ~/Library and then click Go.
  • Open the Containers folder and Ctrl+click each of these folders and Move to Trash. Note that some of these folders may not be present.
    • com.microsoft.errorreporting
    • com.microsoft.Excel
    • com.microsoft.netlib.shipassertprocess
    • com.microsoft.Office365ServiceV2
    • com.microsoft.Outlook
    • com.microsoft.Powerpoint
    • com.microsoft.RMS-XPCService
    • com.microsoft.Word
    • com.microsoft.onenote.mac
  • Click the back arrow to go back to the Library folder and open Group Containers. Ctrl+click each of these folders if present, and Move to Trash.
    • UBF8T346G9.ms
    • UBF8T346G9.Office
    • UBF8T346G9.OfficeOsfWebHost

Finally, remove any Office applications from your Dock and restart your Mac.

Once your Mac has restarted, you'll be able to reinstall Office and your Outlook searching will (hopefully) work again.

macOS Error: /bin/bash: bad interpreter: Operation not permitted

Posted 12/31/2019 1:47 PM by Corey Klass

I recently attempted to execute a Bash script in Terminal on my Mac but received an error message:

/bin/bash: bad interpreter: Operation not permitted

It turns out that this is often due to the "quarantine" filesystem metadata (extended attributes) being set for the file, preventing it from being executed.

To view the extended attributes for a file (called "my-file.sh"), execute the command:

xattr -l my-file.sh

You should see one of the attributes listed as being set as com.apple.quarantine. To remove it from the file, execute:

xattr -d com.apple.quarantine my-file.sh

If you view the extended attributes list again, you should now see the "quarantine" attribute is gone and you can execute the script.

Enable SQL Server AlwaysOn High Availability

Posted 12/06/2019 10:55 AM by Corey Klass

SQL Server AlwaysOn High Availability is an excellent replication option if you have the need for standby or read-only database servers.

In order to use it in SQL Server Management Studio, you first need to enable it in the SQL Server Configuration Manager, then restart your SQL instance.

1. Open the Start Menu and launch the SQL Server Configuration Manager. Start Menu

2. Select the SQL Server Services option in the left pane, then look for the appropriate SQL Server instance in the right pane. SQL Server Configuration Manager

3. Right-click on the SQL Server instance in the right-pane, and select Properties. SQL Server Instance Selection

4. Click the AlwaysOn High Availability tab. Check the Enable AlwaysOn Availability Groups checkbox if it is not already checked. Enable AlwaysOn

5. When prompted that you need to restart your SQL Server instance, click Yes. Update Confirmation

6. You can then launch the Services administrative tool and restart your SQL Server service to enable AlwaysOn Availability Groups in SQL Server Management Studio.

Angular: Auto-Refresh JWT (JSON Web Token) Authentication

Posted 10/15/2019 9:31 AM by Corey Klass

The applications that I've implemented in Angular 4+ with HttpClient from @angular/common/http utilize JSON Web Tokens (JWT) for authentication from our server, which are then stored in the Angular app and passed in an Authentication header to the web server for any API calls.

This works well until the JWT expires, in my case after two hours, at which point any HTTP requests start failing because of the expired token.

Rather than having to implement JWT refresh code in every HTTP call, I've instead written a drop-in replacement service for HttpClient that performs the refresh authentication automatically. You call the .get() and .post() methods as you would normally for HttpClient.

The full code can be found here, with a breakdown of what's going on below:

import {Injectable} from '@angular/core';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {Observable, Subscriber} from 'rxjs';


@Injectable()

export class CkHttpClientService {

  // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  // Populate your own Refresh token value here
  // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  refreshTokenValue: string = null;



  // constructor
  constructor(private httpClient: HttpClient) { }



  // is the specified error an auth error?
  private _isAuthError(error: HttpErrorResponse): boolean {
    // default that it's not?
    let authError = false;

    // if an error was included
    if (error) {
      // check the statuses for an auth error
      authError = authError || (error.status === 401);
      authError = authError || (error.status === 403);
    }

    return authError;
  }




  // refreshes the login token
  private _refreshToken(): Observable<boolean> {
    const observable = new Observable((subscriber: Subscriber<boolean>) => {

      // if there is no refresh token value
      if ((this.refreshTokenValue || '') !== '') {
        subscriber.next(false);
        subscriber.complete();

      // if there is a refresh token value
      } else {
        // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        // Your Login Token refresh code goes here
        // - Make sure to store the new refresh token for later use
        // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        this.refreshTokenValue = '';

        subscriber.next(true);
        subscriber.complete();
      }
    });

    return observable;
  }






  // performs a GET operation
  get(url: string, options?: any): Observable<any> {
    return this._http('get', url, null, options);
  }



  // performs a POST operation
  post(url: string, payload: any, options?: any): Observable<any> {
    return this._http('post', url, payload, options);
  }


  // returns the appropriate HttpClient Observable
  private _httpClient(method: string, url: string, payload: any, options: any): Observable<any> {
    // where we're storing our HTTP Client observable
    let httpClientObservable: Observable<any> = null;

    // if this is a POST
    if (method.toLowerCase() === 'post') {
      httpClientObservable = this.httpClient.post(url, payload, options);

      // default to a GET
    } else {
      httpClientObservable = this.httpClient.get(url, options);
    }

    return httpClientObservable;
  }



  // generic HTTP caller
  private _http(method: string, url: string, payload: any, options: any): Observable<any> {
    const observable = Observable.create((subscriber: Subscriber<any>) => {

      // execute the HTTP observable
      this._httpClient(method, url, payload, options).subscribe((result: any) => {
        // on success
        subscriber.next(result);
        subscriber.complete();

      // on error
      }, (error: HttpErrorResponse) => {
        // is this an auth error?
        if (this._isAuthError(error)) {

          // call the refresh token function
          this._refreshToken().subscribe((refreshSuccessFlag: boolean) => {

            // if the refresh was successful
            if (refreshSuccessFlag) {

              // re-attempt the observable
              this._httpClient(method, url, payload, options).subscribe((retryResult: any) => {
                // on success, send the result
                subscriber.next(retryResult);
                subscriber.complete();

              // on error
              }, (retryError: HttpErrorResponse) => {
                subscriber.error(retryError);
                subscriber.complete();
              });

            // if the refresh failed
            } else {
              subscriber.error(error);
              subscriber.complete();
            }
          });

        // if this is not an auth error
        } else {
          subscriber.error(error);
          subscriber.complete();
        }
      });
    });

    return observable;
  }



}

Here is an explanation of what's going on.

refreshTokenValue: string = null;

This is a string variable that stores the login refresh token, and will be used to refresh the token when it expires. You should populate this when the user initially logs in, or you can replace it with a function or getter that refers to another service.

constructor(private httpClient: HttpClient) { }

Here we're injecting httpClient from @angular/common/http.

private _isAuthError(error: HttpErrorResponse): boolean {
  // default that it's not?
  let authError = false;

  // if an error was included
  if (error) {
    // check the statuses for an auth error
    authError = authError || (error.status === 401);
    authError = authError || (error.status === 403);
  }

  return authError;
}

This function determines if the HTTP error is an authentication error. We're using the HTTP responses statuses of 401 (Unauthorized) and 403 (Forbidden). We first check that error is a defined object.

private _refreshToken(): Observable<boolean> {
  const observable = Observable.create((subscriber: Subscriber<boolean>) => {

    // if there is no refresh token value
    if ((this.refreshTokenValue || '') !== '') {
      subscriber.next(false);
      subscriber.complete();

    // if there is a refresh token value
    } else {
      // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      // Your Login Token refresh code goes here
      // - Make sure to store the new refresh token for later use
      // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      this.refreshTokenValue = '';

      subscriber.next(true);
      subscriber.complete();
    }
  });

  return observable;
}

If there is no refresh token stored, the function returns false by default. You'll need to swap out the dummy refresh token code here with your own call to refresh the login token.

get(url: string, options?: any): Observable<any> {
  return this._http('get', url, null, options);
}

post(url: string, payload: any, options?: any): Observable<any> {
  return this._http('post', url, payload, options);
}

These functions mimic HttpClient from @angular/common/http, but internally refer to a common, private _http function, since the code is mostly identical. I haven't implemented OPTIONS or PUT or any other methods, but you should be able to yourself.

private _httpClient(method: string, url: string, payload: any, options: any): Observable<any> {
  // where we're storing our HTTP Client observable
  let httpClientObservable: Observable<any> = null;

  // if this is a POST
  if (method.toLowerCase() === 'post') {
    httpClientObservable = this.httpClient.post(url, payload, options);

  // default to a GET
  } else {
    httpClientObservable = this.httpClient.get(url, options);
  }

  return httpClientObservable;
}

This function returns the appropriate GET or POST Observable, based on the method value passed to it. We'll be using this function multiple times in _http().

private _http(method: string, url: string, payload: any, options: any): Observable<any> {
  const observable = Observable.create((subscriber: Subscriber<any>) => {

The bulk of the heavy lifting is done in this function, performing the initial HTTP request, refreshing the token if we receive an authentication error, and performing the subsequent HTTP request after the token is refreshed.

    this._httpClient(method, url, payload, options).subscribe((result: any) => {
      // on success
      subscriber.next(result);
      subscriber.complete();

    // on error
    }, (error: HttpErrorResponse) => {
      // is this an auth error?
      if (this._isAuthError(error)) {

We first try performing the initial HTTP request. If it was successful, we pass through the result. Otherwise if it errors, we test to see if it was an authentication error.

        // call the refresh token function
        this._refreshToken().subscribe((refreshSuccessFlag: boolean) => {

If it was an authentication error, we call the _refreshToken() function to perform the refresh and return a success indicator.

          // if the refresh was successful
          if (refreshSuccessFlag) {

            // re-attempt the observable
            this._httpClient(method, url, payload, options).subscribe((retryResult: any) => {
              // on success, send the result
              subscriber.next(retryResult);
              subscriber.complete();

If the refresh was successful, we re-attempt the HTTP request that we performed earlier, passing through the result if it was successful.

            // on error
            }, (retryError: HttpErrorResponse) => {
              subscriber.error(retryError);
              subscriber.complete();
            });

If the HTTP request was unsuccessful, we pass through the error.

          // if the refresh failed
          } else {
            subscriber.error(error);
            subscriber.complete();
          }
        });

If the token refresh was not successful, pass through that error.

      // if this is not an auth error
      } else {
        subscriber.error(error);
        subscriber.complete();
      }

If the initial HTTP error wasn't an authentication error, we pass that error through.

Create a Things To-Do from MS Outlook with a Link Back to the Email

Posted 06/27/2019 10:30 AM by Corey Klass

I'm a big fan of using Things by Cultured Code as my To-Do manager, as it's very easy to use and allows for the quick creation and management of my To-Dos.

Since I work almost exclusively off my email in Microsoft Outlook at work, I've created an AppleScript that I've assigned to a hotkey in BetterTouchTool that will automatically generate a new Things To-Do from the selected email.

Once my To-Do is complete, however, it's annoying to go back into MS Outlook to find the email that I was referencing, so that I can respond to it.

To solve this problem, I've added a link to each of these To Do's with a custom URL handler that directs me back to the MS Outlook email that I created the To Do from. The email link that is created in the To Do looks like this

outlookemailopener://2019-05-13%2003:07:17%20+0000/My%20Email%20Subject/ck@malcontentboffin.com

I've written a separate AppleScript, that I've saved as an App and modified the info.plist file to register the outlookemailopener handler as the opener for this AppleScript.

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>Outlook Email Opener</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>outlookemailopener</string>
        </array>
    </dict>
</array>

The outlookemailopener AppleScript uses a Spotlight query to search for the email file on your Mac and open it in MS Outlook. Because it uses a combination of the email date, subject, and sender, rather than a randomly-generated internal identifier, this script will work across all of your Macs (because each copy of MS Outlook assigns an email a randomly generated identifier).

set searchQuery to "(com_microsoft_outlook_messageSent == $time.iso(" & theDate & ")) && (com_microsoft_outlook_author_email_addresses == \"*" & theEmail & "*\") && (kMDItemTitle == \"" & theSubject & "*\")"

set searchCmd to "mdfind '" & searchQuery & "'"

You can find the link to two AppleScripts here.

Bind "Create Things To Do.scpt" to a hotkey that you can press while in MS Outlook to create a Things To-Do.

"Open Outlook Email.app" should be picked up by LaunchServices and register the outlookemailopener URL handler.

Access the Angular-CLI Internal Web Server From Another Computer

Posted 10/29/2018 8:19 PM by Corey Klass

By default, the Angular-CLI internal web server only listens on the localhost network interface (127.0.0.1). If you want to access your development web application from another computer, you can start the internal web server with the following command:

ng serve --host 0.0.0.0 --disableHostCheck true

Run the Angular-CLI Internal Web Server on an Alternate Port

Posted 10/20/2018 10:24 AM by Corey Klass

The Angular-CLI internal web server runs on port 4200 by default. To change the port number, launch it with the following command:

ng serve --port 8888

Path-less SASS Imports in your Angular App

Posted 10/14/2018 3:34 PM by Corey Klass

One of the nice features of SASS in your Angular-CLI app is that you can include an @import "variables"; command to include the SASS variable definitions from an external file. You can easily make your SASS import file globally available for @import statements, so that you only refer to it by filename, by modifying your /angular.json file in the following hierarchy: Root -> "projects" -> "my-project-name" -> "architect" -> "build" -> "options"

Under "options", create a new map entry called "stylePreprocessorOptions" if it does not exist. Within that, create an array entry called "includePaths". Within "includePaths", you can specify the relative path to your SASS file from the root of your project. For example, it may be located at "src/assets/sass".