Skip to content

Instantly share code, notes, and snippets.

@abombss
Last active December 10, 2015 20:38
Show Gist options
  • Save abombss/4489558 to your computer and use it in GitHub Desktop.
Save abombss/4489558 to your computer and use it in GitHub Desktop.
Automatically Install AppFabric Cache Cluster and Nodes
function Uninstall-AppFabricCacheNode {
#TODO: Should try and remove the configuration stuff
gwmi win32_product -filter "Name LIKE 'AppFabric%'" |% {
$key="IdentifyingNumber=`"$($_.IdentifyingNumber)`",Name=`"$($_.Name)`",version=`"$($_.Version)`"";
([wmi]"Win32_Product.$key").uninstall()
}
}
function Reset-AppFabricCacheDatabase {
param(
[Parameter(Mandatory=$true)]
[string]$ConnectionString
)
$con = new-object System.Data.SqlClient.SqlConnection
try {
$con.ConnectionString = $ConnectionString
Write-Verbose "Connection to $ConnectionString"
$con.Open()
$cmd = $con.CreateCommand()
$cmd.CommandText="SELECT DB_NAME() AS [Database]"
$dbName = $cmd.ExecuteScalar()
$cmd.Dispose()
Write-Verbose "Found database $dbName"
$cmd = $con.CreateCommand()
$cmd.CommandText = @"
USE master;
ALTER DATABASE [$dbName] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE [$dbName];
"@
Write-Verbose "Dropping database $dbName"
$cmd.ExecuteNonQuery()
$cmd.Dispose()
$cmd = $con.CreateCommand()
$cmd.CommandText = "CREATE DATABASE [$dbName]; ALTER DATABASE [$dbName] SET MULTI_USER"
Write-Verbose "Creating database $dbName"
$cmd.ExecuteNonQuery()
$cmd.Dispose()
$cmd = $null
} catch {
Write-Error $error[0]
} finally {
if ($cmd) { $cmd.Dispose() }
$con.Close()
}
}
function Add-AccountPrivilege {
param([string]$Account, [string]$Privilege="SeServiceLogonRight")
try {
[MyLsaWrapper.LsaWrapperCaller]
} catch {
# Special Powershell Command to Grant the service account LogOn as Service Rights
Add-Type @'
using System;
using System.Collections.Generic;
using System.Text;
namespace MyLsaWrapper
{
using System.Runtime.InteropServices;
using System.Security;
using System.Management;
using System.Runtime.CompilerServices;
using System.ComponentModel;
using LSA_HANDLE = IntPtr;
[StructLayout(LayoutKind.Sequential)]
struct LSA_OBJECT_ATTRIBUTES
{
internal int Length;
internal IntPtr RootDirectory;
internal IntPtr ObjectName;
internal int Attributes;
internal IntPtr SecurityDescriptor;
internal IntPtr SecurityQualityOfService;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct LSA_UNICODE_STRING
{
internal ushort Length;
internal ushort MaximumLength;
[MarshalAs(UnmanagedType.LPWStr)]
internal string Buffer;
}
sealed class Win32Sec
{
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaOpenPolicy(
LSA_UNICODE_STRING[] SystemName,
ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
int AccessMask,
out IntPtr PolicyHandle
);
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
SuppressUnmanagedCodeSecurityAttribute]
internal static extern uint LsaAddAccountRights(
LSA_HANDLE PolicyHandle,
IntPtr pSID,
LSA_UNICODE_STRING[] UserRights,
int CountOfRights
);
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
SuppressUnmanagedCodeSecurityAttribute]
internal static extern int LsaLookupNames2(
LSA_HANDLE PolicyHandle,
uint Flags,
uint Count,
LSA_UNICODE_STRING[] Names,
ref IntPtr ReferencedDomains,
ref IntPtr Sids
);
[DllImport("advapi32")]
internal static extern int LsaNtStatusToWinError(int NTSTATUS);
[DllImport("advapi32")]
internal static extern int LsaClose(IntPtr PolicyHandle);
[DllImport("advapi32")]
internal static extern int LsaFreeMemory(IntPtr Buffer);
}
/// <summary>
/// This class is used to grant "Log on as a service", "Log on as a batchjob", "Log on localy" etc.
/// to a user.
/// </summary>
public sealed class LsaWrapper : IDisposable
{
[StructLayout(LayoutKind.Sequential)]
struct LSA_TRUST_INFORMATION
{
internal LSA_UNICODE_STRING Name;
internal IntPtr Sid;
}
[StructLayout(LayoutKind.Sequential)]
struct LSA_TRANSLATED_SID2
{
internal SidNameUse Use;
internal IntPtr Sid;
internal int DomainIndex;
uint Flags;
}
[StructLayout(LayoutKind.Sequential)]
struct LSA_REFERENCED_DOMAIN_LIST
{
internal uint Entries;
internal LSA_TRUST_INFORMATION Domains;
}
enum SidNameUse : int
{
User = 1,
Group = 2,
Domain = 3,
Alias = 4,
KnownGroup = 5,
DeletedAccount = 6,
Invalid = 7,
Unknown = 8,
Computer = 9
}
enum Access : int
{
POLICY_READ = 0x20006,
POLICY_ALL_ACCESS = 0x00F0FFF,
POLICY_EXECUTE = 0X20801,
POLICY_WRITE = 0X207F8
}
const uint STATUS_ACCESS_DENIED = 0xc0000022;
const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a;
const uint STATUS_NO_MEMORY = 0xc0000017;
IntPtr lsaHandle;
public LsaWrapper()
: this(null)
{ }
// // local system if systemName is null
public LsaWrapper(string systemName)
{
LSA_OBJECT_ATTRIBUTES lsaAttr;
lsaAttr.RootDirectory = IntPtr.Zero;
lsaAttr.ObjectName = IntPtr.Zero;
lsaAttr.Attributes = 0;
lsaAttr.SecurityDescriptor = IntPtr.Zero;
lsaAttr.SecurityQualityOfService = IntPtr.Zero;
lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
lsaHandle = IntPtr.Zero;
LSA_UNICODE_STRING[] system = null;
if (systemName != null)
{
system = new LSA_UNICODE_STRING[1];
system[0] = InitLsaString(systemName);
}
uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr,
(int)Access.POLICY_ALL_ACCESS, out lsaHandle);
if (ret == 0)
return;
if (ret == STATUS_ACCESS_DENIED)
{
throw new UnauthorizedAccessException();
}
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
{
throw new OutOfMemoryException();
}
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
}
public void AddPrivileges(string account, string privilege)
{
IntPtr pSid = GetSIDInformation(account);
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege);
uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1);
if (ret == 0)
return;
if (ret == STATUS_ACCESS_DENIED)
{
throw new UnauthorizedAccessException();
}
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
{
throw new OutOfMemoryException();
}
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
}
public void Dispose()
{
if (lsaHandle != IntPtr.Zero)
{
Win32Sec.LsaClose(lsaHandle);
lsaHandle = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
~LsaWrapper()
{
Dispose();
}
// helper functions
IntPtr GetSIDInformation(string account)
{
LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
LSA_TRANSLATED_SID2 lts;
IntPtr tsids = IntPtr.Zero;
IntPtr tdom = IntPtr.Zero;
names[0] = InitLsaString(account);
lts.Sid = IntPtr.Zero;
Console.WriteLine("String account: {0}", names[0].Length);
int ret = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids);
if (ret != 0)
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret));
lts = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(tsids,
typeof(LSA_TRANSLATED_SID2));
Win32Sec.LsaFreeMemory(tsids);
Win32Sec.LsaFreeMemory(tdom);
return lts.Sid;
}
static LSA_UNICODE_STRING InitLsaString(string s)
{
// Unicode strings max. 32KB
if (s.Length > 0x7ffe)
throw new ArgumentException("String too long");
LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
lus.Buffer = s;
lus.Length = (ushort)(s.Length * sizeof(char));
lus.MaximumLength = (ushort)(lus.Length + sizeof(char));
return lus;
}
}
public class LsaWrapperCaller
{
public static void AddPrivileges(string account, string privilege)
{
using (LsaWrapper lsaWrapper = new LsaWrapper())
{
lsaWrapper.AddPrivileges(account, privilege);
}
}
}
}
'@
#Swallow the exception, because it should be missing type and we just added it
}
# Run the command to grant the account login as service rights
[MyLsaWrapper.LsaWrapperCaller]::AddPrivileges($Account, $Privilege)
}
function Install-AppFabricCacheNode {
param(
[string]$SetupFile=$null,
[string]$LogFile=".\appfabricsetup.txt",
[string]$WorkingDirectory=".",
[string]$Provider=$null,
[string]$ConnectionString=$null,
[string]$ServiceAccount,
[string]$Password,
[int]$CachePort=22233,
[int]$ClusterPort=22234,
[int]$ArbitrationPort=22235,
[int]$ReplicationPort=22236,
[switch]$NewCacheCluster=$false
);
$CurrentHost = ([System.Net.Dns]::GetHostByName(($env:computerName))).HostName
$AbsoluteWorkingDir = Resolve-Path $WorkingDirectory
if (![System.IO.Path]::IsPathRooted($SetupFile)) {
$SetupFile = Resolve-Path $SetupFile
}
if (![System.IO.Path]::IsPathRooted($LogFile)) {
$LogFile = Join-Path (Resolve-Path (Split-Path $LogFile -Parent)) (Split-Path $LogFile -Leaf)
}
$installArgs = @(
"/install"
"cachingservice,cacheclient,cacheadmin"
"/l:`"$LogFile`""
)
$installParameters = @{
FilePath=$SetupFile
ArgumentList=$installArgs
Wait=$true
WorkingDirectory=$AbsoluteWorkingDir
Verb='runas'
}
Write-Verbose "Silently starting appfabric installation"
Start-Process @installParameters
Write-Verbose "Changing credentials of AppFabricCachingService to service account credentials"
& (Join-Path (Join-Path $Env:WinDir system32) sc.exe) @(
'config'
'AppFabricCachingService'
'obj='
"`"$ServiceAccount`""
'password='
"`"$Password`""
)
Write-Verbose "Adding Log On as Service right for Service Account"
try {
Add-AccountPrivilege -Account $ServiceAccount -Privilege "SeServiceLogonRight"
} catch {
Add-AccountPrivilege -Account $ServiceAccount -Privilege "SeServiceLogonRight"
}
try {
Add-AccountPrivilege -Account $ServiceAccount -Privilege "SeBatchLogonRight"
} catch{
Add-AccountPrivilege -Account $ServiceAccount -Privilege "SeBatchLogonRight"
}
Write-Verbose "Adding Scheduled Task to Start-CacheHost at machine boot"
# In 2012 this becomes easier because there is a cmdlet for schedule task administration
$scheduledTaskArgs = @(
'/Create',
'/TN',"AppFabricCache-StartCacheHost"
'/SC','ONSTART',
'/RL','Highest',
'/RU',"`"$ServiceAccount`"",
'/RP',"`"$Password`"",
'/DELAY',"0000:30"
'/F',
'/TR',"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy RemoteSigned -NoProfile -NoLogo -Command {import-module DistributedCacheAdministration; use-cachecluster; start-cachehost -hostname $CurrentHost -cacheport $CachePort;}"
)
& (Join-Path (Join-Path $Env:WinDir system32) schtasks.exe) $scheduledTaskArgs
Write-Verbose "Opening Firewall for caching ports"
# Open the firewall ports, run on each node in the cluster
# OK if all of these don't run because some may already be open, look into a better way to verify the ports are open
netsh advfirewall firewall set rule group="Appfabric Server: AppFabric Caching Service" new enable=Yes
netsh advfirewall firewall set rule name="Remote Service Management (RPC)" profile=domain new enable=Yes
netsh advfirewall firewall set rule name="Remote Service Management (RPC-EPMAP)" profile=domain new enable=Yes
netsh advfirewall firewall set rule name="Remote Service Management (NP-In)" profile=domain new enable=Yes
# Hack, manually add the appfab powershell module path,
# look into registery settings or something better to get the location of the module path
# or see if wmi will work to get the new PSModulePath value and then we can splice it into the current PSModulePath
#
$Env:PSModulePath += ";c:\Program Files\AppFabric 1.1 for Windows Server\PowershellModules"
Import-Module DistributedCacheAdministration
Import-Module DistributedCacheConfiguration
if ($NewCacheCluster) {
Write-Verbose "Creating a new cache cluster"
# TODO: Parameterize this command better
New-CacheCluster -Provider $Provider -ConnectionString $ConnectionString -Size Small
}
Use-CacheCluster -Provider $Provider -ConnectionString $ConnectionString
Write-Verbose "Registering cache host"
Register-CacheHost -HostName $CurrentHost -Provider $Provider -ConnectionString $ConnectionString -Account $ServiceAccount -CachePort $CachePort -ClusterPort $ClusterPort -ArbitrationPort $ArbitrationPort -ReplicationPort $ReplicationPort
Write-Verbose "Adding the cache host"
Add-CacheHost -Provider $Provider -ConnectionString $ConnectionString -Account $ServiceAccount
Add-CacheAdmin -Provider $Provider -ConnectionString $ConnectionString
Set-CacheHostConfig -IsLeadHost $true -HostName $CurrentHost -CachePort $CachePort
Set-CacheConnectionString -Provider $Provider -ConnectionString $ConnectionString
if ($NewCacheCluster) {
Write-Verbose "Starting cache cluster"
Start-CacheCluster
} else {
Write-Verbose "Starting cache host"
Start-CacheHost -hostname $CurrentHost -cacheport $CachePort
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment