# Manual Testing section - put stuff here for manually testing script - typically parameters:
#=================================================================================
#=================================================================================
# Constants section - modify stuff here:
#=================================================================================
# Assign script name variable for use in event logging.
# ScriptName should be the same as the ID of the module that the script is contained in
$ScriptName = "SCOM2019.RunAsHelper.7002EventScript.DS.ps1"
$EventID = "7003"
#=================================================================================
# Starting Script section - All scripts get this
#=================================================================================
# Gather the start time of the script
$StartTime = Get-Date
#Set variable to be used in logging events
$whoami = whoami
# Load MOMScript API
$momapi = New-Object -comObject MOM.ScriptAPI
#Log script event that we are starting task
$momapi.LogScriptEvent($ScriptName,$EventID,0,"`n Script is starting. `n Running as ($whoami).")
#=================================================================================
# PropertyBag Script section - Monitoring scripts get this
#=================================================================================
# Load SCOM PropertyBag function
$bag = $momapi.CreatePropertyBag()
#=================================================================================
# Begin MAIN script section
#=================================================================================
# The following section is adapted from https://gallery.technet.microsoft.com/scriptcenter/Grant-Revoke-Query-user-26e259b0
Set-StrictMode -Version 2.0
Add-Type -TypeDefinition @'
using System;
namespace PS_LSA
{
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using LSA_HANDLE = IntPtr;
public enum Rights
{
SeServiceLogonRight, // Log on as a service
}
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 AddPrivilege(string account, Rights privilege)
{
uint ret = 0;
using (Sid sid = new Sid(account))
{
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege.ToString());
ret = Win32Sec.LsaAddAccountRights(lsaHandle, sid.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 string[] EnumerateAccountsWithUserRight(Rights privilege, bool resolveSid = true)
{
uint ret = 0;
ulong count = 0;
LSA_UNICODE_STRING[] rights = new LSA_UNICODE_STRING[1];
rights[0] = InitLsaString(privilege.ToString());
IntPtr buffer = IntPtr.Zero;
string[] accounts = null;
ret = Win32Sec.LsaEnumerateAccountsWithUserRight(lsaHandle, rights, out buffer, out count);
if (ret == 0)
{
accounts = new string[count];
for (int i = 0; i < (int)count; i++)
{
LSA_ENUMERATION_INFORMATION LsaInfo = (LSA_ENUMERATION_INFORMATION)Marshal.PtrToStructure(
IntPtr.Add(buffer, i * Marshal.SizeOf(typeof(LSA_ENUMERATION_INFORMATION))),
typeof(LSA_ENUMERATION_INFORMATION));
if (resolveSid) {
try {
accounts[i] = (new SecurityIdentifier(LsaInfo.PSid)).Translate(typeof(NTAccount)).ToString();
} catch (System.Security.Principal.IdentityNotMappedException) {
accounts[i] = (new SecurityIdentifier(LsaInfo.PSid)).ToString();
}
} else { accounts[i] = (new SecurityIdentifier(LsaInfo.PSid)).ToString(); }
}
Win32Sec.LsaFreeMemory(buffer);
return accounts;
}
if (ret == STATUS_NO_MORE_ENTRIES) return null; // No accounts assigned
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(); }
#Log the params to the script:
$momapi.LogScriptEvent($ScriptName,$EventID,0,"`n Params passed to script: `n Domain: ($Domain) `n UserName: ($UserName) `n EventDescription: $EventDescription")
#Get existing accounts with SeServiceLogonRight
$AccountList = ""
$Error.Clear
$lsa = New-Object PS_LSA.LsaWrapper
$sids = $lsa.EnumerateAccountsWithUserRight("SeServiceLogonRight", $false)
IF ($Error)
{
$Result = "Error attempting to enumerate existing accounts. `n No modifications were made. `n Error is ($Error)"
$momapi.LogScriptEvent($ScriptName,$EventID,0,"`n Error attempting to enumerate existing accounts. `n No modifications were made. `n Error is ($Error)")
}
ELSE
{
FOREACH ($sid in $sids)
{
[string]$SidText = $sid
TRY
{
$objSID = New-Object System.Security.Principal.SecurityIdentifier($sid)
$objUser = $objSID.Translate([System.Security.Principal.NTAccount])
$AccountName = $objUser.Value
}
CATCH
{
$AccountName = "unresolved"
}
$AccountList = $AccountList + $AccountName + " " + $SidText + "`n"
}
$momapi.LogScriptEvent($ScriptName,$EventID,0,"`n The account list before modification for Log on as a service right is: `n $AccountList")
#Add account to user right
$Account = "$Domain\$UserName"
$Error.Clear
$lsa = New-Object PS_LSA.LsaWrapper
$lsa.AddPrivilege($Account,"SeServiceLogonRight")
IF ($Error)
{
$Result = "Error attempting to grant the Log on as a service privilege to account: ($Account). `n Error is ($Error)."
$momapi.LogScriptEvent($ScriptName,$EventID,0,"`n Error attempting to grant the Log on as a service privilege to account: ($Account). `n Error is ($Error).")
}
ELSE
{
$Result = "User ($Account) was granted the Log on as a service privilege."
$momapi.LogScriptEvent($ScriptName,$EventID,0,"`n User ($Account) was granted the Log on as a service privilege.")
}
#Get accounts with SeServiceLogonRight after modification
$AccountListAfter = ""
$Error.Clear
$lsa = New-Object PS_LSA.LsaWrapper
$sids = $lsa.EnumerateAccountsWithUserRight("SeServiceLogonRight", $false)
IF ($Error)
{
$momapi.LogScriptEvent($ScriptName,$EventID,0,"`n Error attempting to enumerate accounts after modification. `n Error is ($Error)")
}
ELSE
{
FOREACH ($sid in $sids)
{
[string]$SidText = $sid
TRY
{
$objSID = New-Object System.Security.Principal.SecurityIdentifier($sid)
$objUser = $objSID.Translate([System.Security.Principal.NTAccount])
$AccountName = $objUser.Value
}
CATCH
{
$AccountName = "unresolved"
}
$AccountListAfter = $AccountListAfter + $AccountName + " " + $SidText + "`n"
}
$momapi.LogScriptEvent($ScriptName,$EventID,0,"`n The account list after modification for Log on as a service right is: `n $AccountListAfter")
}
}