I recently reworked this awesome code from Michael Murgolo to set the time zone of a Windows computer using PowerShell.
To use the script, just pass the name of a valid time zone as listed in the registry under HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
.
For example, to change the time zone to "Central America Standard Time":
powershell.exe -file timezone.ps1 "Central America Standard Time"
Here is the code:
param($TimeZone)
Add-Type -TypeDefinition @'
using System;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace NSPrivileges {
public class TokenPrivileges {
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int OpenProcessToken(int ProcessHandle, int DesiredAccess, ref int tokenhandle);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetCurrentProcess();
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int LookupPrivilegeValue(string lpsystemname, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int AdjustTokenPrivileges(int tokenhandle, int disableprivs, [MarshalAs(UnmanagedType.Struct)] ref TOKEN_PRIVILEGE Newstate, int bufferlength, int PreivousState, int Returnlength);
public const int TOKEN_ASSIGN_PRIMARY = 0x00000001;
public const int TOKEN_DUPLICATE = 0x00000002;
public const int TOKEN_IMPERSONATE = 0x00000004;
public const int TOKEN_QUERY = 0x00000008;
public const int TOKEN_QUERY_SOURCE = 0x00000010;
public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public const int TOKEN_ADJUST_GROUPS = 0x00000040;
public const int TOKEN_ADJUST_DEFAULT = 0x00000080;
public const UInt32 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001;
public const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
public const UInt32 SE_PRIVILEGE_REMOVED = 0x00000004;
public const UInt32 SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000;
public static void EnablePrivilege(string privilege) {
var token = 0;
var TP = new TOKEN_PRIVILEGE();
var LD = new LUID();
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref token);
LookupPrivilegeValue(null, privilege, ref LD);
TP.PrivilegeCount = 1;
var luidAndAtt = new LUID_AND_ATTRIBUTES {Attributes = SE_PRIVILEGE_ENABLED, Luid = LD};
TP.Privilege = luidAndAtt;
AdjustTokenPrivileges(token, 0, ref TP, 1024, 0, 0);
}
public static void DisablePrivilege(string privilege) {
var token = 0;
var TP = new TOKEN_PRIVILEGE();
var LD = new LUID();
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref token);
LookupPrivilegeValue(null, privilege, ref LD);
TP.PrivilegeCount = 1;
var luidAndAtt = new LUID_AND_ATTRIBUTES {Luid = LD};
TP.Privilege = luidAndAtt;
AdjustTokenPrivileges(token, 0, ref TP, 1024, 0, 0);
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LUID {
internal uint LowPart;
internal uint HighPart;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LUID_AND_ATTRIBUTES {
internal LUID Luid;
internal uint Attributes;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TOKEN_PRIVILEGE {
internal uint PrivilegeCount;
internal LUID_AND_ATTRIBUTES Privilege;
}
}
}
namespace NSTimeZone {
public class TimeZoneControl {
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool SetDynamicTimeZoneInformation([In] ref DYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation);
public static void SetDynamicTimeZone(DYNAMIC_TIME_ZONE_INFORMATION dtzi) {
SetDynamicTimeZoneInformation(ref dtzi);
}
public static REG_TZI_FORMAT GetRegTziFormat(byte[] tziRegValue) {
REG_TZI_FORMAT rtzi;
object varValue = tziRegValue;
byte[] baData = varValue as byte[];
int iSize = baData.Length;
IntPtr buffer = Marshal.AllocHGlobal(iSize);
Marshal.Copy(baData, 0, buffer, iSize);
rtzi = (REG_TZI_FORMAT)Marshal.PtrToStructure(buffer,typeof(REG_TZI_FORMAT));
Marshal.FreeHGlobal(buffer);
return rtzi;
}
}
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct SYSTEM_TIME {
public short year;
public short month;
public short dayOfWeek;
public short day;
public short hour;
public short minute;
public short second;
public short milliseconds;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DYNAMIC_TIME_ZONE_INFORMATION {
public int bias;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string standardName;
public SYSTEM_TIME standardDate;
public int standardBias;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string daylightName;
public SYSTEM_TIME daylightDate;
public int daylightBias;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string timeZoneKeyName;
public bool dynamicDaylightTimeDisabled;
}
[StructLayout(LayoutKind.Sequential)]
public struct REG_TZI_FORMAT {
public int bias;
public int standardBias;
public int daylightBias;
public SYSTEM_TIME standardDate;
public SYSTEM_TIME daylightDate;
}
}
'@
$TimeZonesPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
$TimeZonePath = "$TimeZonesPath\$TimeZone"
$TimeZoneInfoPath = "SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
# Exit if the requested time zone is invalid.
if (! (Test-Path HKLM:$TimeZonePath)) {
Write-Host "The time zone $TimeZone does not exist."; return
}
$ExistingTimeZone = (Get-ItemProperty -Path HKLM:$TimeZoneInfoPath -Name TimeZoneKeyName).TimeZoneKeyName
# Exit if the time zone does not need to be changed.
if ($TimeZone -eq $ExistingTimeZone) {
Write-Host "The time zone is already set to $TimeZone."; return
}
# Get the time zone properties from the registry.
$TimeZoneProperties = @{}
Get-Item HKLM:$TimeZonePath | Select-Object -ExpandProperty property | %{
$TimeZoneProperties.Add($_, (Get-ItemProperty HKLM:$TimeZonePath -Name $_).$_)
}
# Interpret the time zone information.
$TimeZoneInfo = [NSTimeZone.TimeZoneControl]::GetRegTziFormat($TimeZoneProperties.TZI)
$DynamicTimeZoneInfo = New-Object NSTimeZone.DYNAMIC_TIME_ZONE_INFORMATION
$DynamicTimeZoneInfo.bias = $TimeZoneInfo.Bias
$DynamicTimeZoneInfo.standardBias = $TimeZoneInfo.standardBias
$DynamicTimeZoneInfo.daylightBias = $TimeZoneInfo.daylightBias
$DynamicTimeZoneInfo.standardName = @($TimeZoneProperties.MUI_Std, $TimeZoneProperties.Std)[$TimeZoneProperties.MUI_Std -eq ""]
$DynamicTimeZoneInfo.daylightName = @($TimeZoneProperties.MUI_Dlt, $TimeZoneProperties.Dlt)[$TimeZoneProperties.MUI_Dlt -eq ""]
$DynamicTimeZoneInfo.timeZoneKeyName = $TimeZone
$DynamicTimeZoneInfo.standardDate = $TimeZoneInfo.standardDate
$DynamicTimeZoneInfo.daylightDate = $TimeZoneInfo.daylightDate
$DynamicTimeZoneInfo.dynamicDaylightTimeDisabled = $false
# Enable the privilege required to set the time zone.
[NSPrivileges.TokenPrivileges]::EnablePrivilege('SeTimeZonePrivilege') | Out-Null
# Set the time zone.
[NSTimeZone.TimeZoneControl]::SetDynamicTimeZone($DynamicTimeZoneInfo)
# Disable the privilege required to set the time zone.
[NSPrivileges.TokenPrivileges]::DisablePrivilege('SeTimeZonePrivilege') | Out-Null