Category Archives: Powershell

Automating Compute Engine Local SSD configuration in Windows


Similar to other public cloud providers, Google Cloud offers the ability to attach local high-speed disks to virtual machines (VMs). This offering is called Local SSD.

The “Local” in Local SSD means that the disks are physically attached to the hypervisor host where the VM is executing. This provides the VM with high-speed/low-latency data operations over the NVME interface.

On Windows GCE instances (VMs), Local SSD volumes are typically used for temporary or ephemeral data such as the Windows Pagefile, Microsoft SQL Server Temp database, or other high-speed caching needs.


Certain GCE instance machine sizes come with different quantities of Local SSD disks, which are always 375 GB in size. They can be striped together to create larger volumes with higher performance using logical volume management tools in the Operating System.

Read more about Local SSD Performance.


However, again like other public clouds, Local SSD storage is ephemeral and comes with some risks.

Data on volumes created with Local SSD disks can be irretrievably lost and no guarantee is made as to the safety or durability of that data.

Specifically, if the OS is shut down from within the Guest Operating System, the GCE instance will power off and the Local SSD disks and the data they contain will be lost. When the VM is started back up via the Cloud Console, it will have new, empty Local SSD disks which must be initialized again in order to be used.

There are other situations where data on Local SSD disks can be lost, such as if the hypervisor host has an issue and Google Cloud cannot migrate the Local SSD data along with the VM to a new host.

Read more about Local SSD data persistence.

So, generally speaking, Local SSDs offer great performance but the usage of them needs to be understood and the loss of data should not impact the application.

Usage with localssd_init

In Google Cloud, Local SSD disks show up as raw disks that need to be initialized and formatted before they can be used.

To automate the initialization of Local SSDs on Windows GCE instances and create usable volumes, I have developed a simple PowerShell script called localssd_init.ps1 which can be found in my GitHub repository gce-localssd-init-powershell.

The script is configured to check if certain drive letters are present. If the drive letters are missing, it will recreate them using a specific configuration of Local SSD disks.

To use the script, simply copy it to your server and then sign it or configure the ExecutionPolicy.

Next, edit the localssd_init.ps1 script and configure the volumes that will be created using Local SSD disks, starting around line 50:

$LocalSSDConfig = @(
    [LocalSSDVol]@{Name = "SQLTempDB"; DriveLetter = 'E'; LocalSSDQty = 2; NTFSAlloc = '65536' },
    [LocalSSDVol]@{Name = "Pagefile"; DriveLetter = 'P'; LocalSSDQty = 2; NTFSAlloc = '8192'; PostScript = "C:\path\to\pagefile.ps1" }

Add, remove, or modify entries in the array. Be sure to have a comma after each line, except for the last line, and separate the key=value pairs with a semicolon.

For each entry,

  • Update the Name and DriveLetter where the volume will be mounted. The name will be set for the Storage Pool and Volume.
  • Set the LocalSSDQty to the number of 375 GB Local SSD disks to stripe across and set the NTFSAlloc to the needed NTFS Allocation unit size.

Optionally, set PostScript to the path to a custom script to run after the volume has been created. The custom script could change the system Pagefile configuration to use the new drive (a reboot will be be required) or restart SQL Server so it recreates the Temp database files.

The script uses Windows Storage Spaces to create a new Storage Pool using the necessary quantity of Local SSD volumes using “Simple” resiliency which is the same as Striping and then creates a new Volume using the maximum size of the pool and formats it using NTFS with the required allocation size and mounts it at the required drive letter.

During server creation, the localssd_init.ps1 script can be used to create the Local SSD-backed volumes and then run at every subsequent boot to make sure they exist and recreate them if they are missing.

Simply run the script and the disks will be created. The script will log to the standard output and also create entries in the System Event Log.

To enable the script to run at every boot, use this snippet to configure a new Windows Task Manager job to run at startup. Be sure to update the path to the script:

  Set-ExecutionPolicy RemoteSigned
  $trigger = new-jobtrigger -atstartup -randomdelay 00:00:10
  register-scheduledjob -trigger $trigger -filepath $path -name localssd_init


If you are on the fence about using Local SSD on Windows GCE instances because those disks might need to be initialized again after an outage, check out localssd_init.ps1 to make sure they’re always available for use.

Fix for Network Level Authentication (NLA) restriction with RDP

While doing some testing with a Windows virtual machine in Google Cloud, I suddenly received the terrible Network Level Authentication (NLA) message when trying to RDP:

The remote computer that you are trying to connect to requires network level authentication (NLA), but your windows domain controller cannot be contacted to perform NLA. If you are an administrator on the remote computer, you can disable NLA by using the options on the remote tab of the System Properties dialog box.

It’s easy enough to fix when a VM console is available, but cloud VMs do not have graphical consoles, so I had to take a different approach.

PowerShell, as usual

PowerShell can leverage WMI to make operating system configuration changes remotely as long as the needed ports are open and an administrator account is available.

Follow along for the easy fix to temporarily disable NLA in order to successfully RDP.

First, create a PSCredential object called $credential and with an administrator account (local or domain):

$credential = New-Object System.Management.Automation.PSCredential "instance-1\administrator", $(ConvertTo-SecureString "mysecurepasswd" -AsPlainText -Force)

Replace ‘instance-1’ with the hostname of the server or the AD domain, ‘administrator’ with the account username, and ‘mysecurepasswd’ with the password for the account.

Once the $credential object is created, use Get-WmiObject to check the value of UserAuthenticationRequired. When NLA is active, this value is set to ‘1’:

Get-WmiObject -class "Win32_TSGeneralSetting" -Namespace root\cimv2\terminalservices -computer instance-1 -filter "TerminalName='RDP-tcp'" -Credential $credential

Replace ‘instance-1’ with the hostname, IP, or FQDN of the server.

Result of WMI call showing UserAuthenticationRequired is set to 1 preventing RDP due to NLA

If UserAuthenticationRequired is set to ‘1’, disable it by setting it to ‘0’.

(Get-WmiObject -class "Win32_TSGeneralSetting" -Namespace root\cimv2\terminalservices -computer instance-1 -filter "TerminalName='RDP-tcp'" -Credential $credential).SetUserAuthenticationRequired(0)

As before, change ‘instance-1’ with the hostname, IP, or FQDN of the server.

Note the parenthesis at the start of Get-WmiObject – the command is actually calling the SetUserAuthenticationRequired() method on the object returned by Get-WmiObject.

The SetUserAuthenticationRequired() method returned some data but it’s not clear if the value was set successfully or not.

Result of SetUserAuthenticationRequired() method call

Run the Get-WmiObject again and check the UserAuthenticationRequired value.

Get-WmiObject -class "Win32_TSGeneralSetting" -Namespace root\cimv2\terminalservices -computer instance-1 -filter "TerminalName='RDP-tcp'" -Credential $credential

Replace ‘instance-1’ with the hostname, IP, or FQDN of the server.

Result of WMI call showing UserAuthenticationRequired is set to 0 permitting RDP

Once I saw UserAuthenticationRequired was set to ‘0’, I was able to RDP again.

Based on: