Powershell : Event Log Readers (Add and Verify)


Managing user permissions across multiple servers is a common task that requires efficiency and reliability. This post details my journey of creating a PowerShell script to add a service account to the "Event Log Readers" group across numerous servers using PsExec.

The Challenge

I needed to add a service account (bear\EventAgent) to the "Event Log Readers" local group on multiple Windows servers. The requirements were:

  1. Read server names from a text file
  2. Connect to each server remotely
  3. Add the account to the "Event Log Readers" group
  4. Verify the operation was successful
  5. Provide detailed feedback throughout the process

First Attempt: PowerShell Remoting

My initial approach used PowerShell remoting with Invoke-Command:

# First attempt using PowerShell Remoting
foreach ($server in $servers) {
    if (Test-Connection -ComputerName $server -Count 1 -Quiet) {
        try {
            # Attempt to connect and run command
            $result = Invoke-Command -ComputerName $server -ScriptBlock {
                net localgroup "Event Log Readers" bear\EventAgent /add
            } -ErrorAction Stop
            
            # Display the result
            Write-Host "Command executed on $server with output:" -ForegroundColor Green
            $result
        }
        catch {
            Write-Host "ERROR: Failed to execute command on $server" -ForegroundColor Red
            Write-Host "Error details: $_" -ForegroundColor Red
        }
    }
}

This approach failed on several servers with WinRM connection errors:

ERROR: Failed to execute command on mgrworkstation1
Error details: [mgrworkstation1] Connecting to remote server mgrworkstation failed with the 
following error message : The client cannot connect to the destination specified in the 
request. Verify that the service on the destination is running and is accepting requests...

Second Approach: PsExec

To overcome the WinRM limitations, I switched to Sysinternals' PsExec utility, which doesn't rely on WinRM being configured:

# Using PsExec to run the command
$command = "net localgroup `"Event Log Readers`" bear\eventagent /add"
$result = & $psExecPath "\\$server" -s cmd /c $command 2>&1

This worked better but produced confusing output. PsExec would show:

ERROR: Command execution failed on mgrworkstation1
Starting cmd on mgrworkstation1.. 
cmd exited on mgrworkstation1 with error code 0.

Despite the "ERROR" message, an exit code of 0 indicates success. This required better parsing logic.

Final Solution

The final script addresses all requirements with several enhancements:

Group Existence Check

Before attempting to add the user, verify the group exists:

# Check if the group exists
$checkCommand = "net localgroup `"$groupName`""
$checkResult = & $psExecPath "\\$server" -s cmd /c $checkCommand 2>&1

if ($checkResult -match "system error|does not exist") {
    Write-Host "ERROR: The group '$groupName' does not exist on $server" -ForegroundColor Red
    $failCount++
    continue
}

Membership Verification

Check if the user is already a member of the group:

# Check if user is already in the group
if ($checkResult -match [regex]::Escape($userToAdd)) {
    Write-Host "INFO: User $userToAdd is already a member of $groupName on $server" 
    ForegroundColor Cyan
    $alreadyExistsCount++
    $successCount++
    continue
}

Handling PsExec's "Error Code 0" Messages

Properly interpret PsExec's seemingly misleading output:

# Special case for PsExec showing "error code 0" but command was successful
elseif ($result -match "exited .* with error code 0") {
    Write-Host "Command executed successfully on $server (exit code 0)" 
   -ForegroundColor Green
    $result | ForEach-Object { Write-Host "  $_" -ForegroundColor White }
    
    $successCount++
    
    # Verify the user was added
    $verifyCommand = "net localgroup `"$groupName`""
    $verifyResult = & $psExecPath "\\$server" -s cmd /c $verifyCommand 2>&1
    
    if ($verifyResult -match [regex]::Escape($userToAdd)) {
        Write-Host "Verified: User $userToAdd is now a member of $groupName on $server" 
       -ForegroundColor Green
    } else {
        Write-Host "WARNING: Verification failed. Please check manually." 
       -ForegroundColor Yellow
    }
}

4. Detailed Execution Summary

Provide a comprehensive breakdown of results:

# Display summary
Write-Host "`n===================================" -ForegroundColor Magenta
Write-Host "EXECUTION SUMMARY" -ForegroundColor Magenta
Write-Host "===================================" -ForegroundColor Magenta
Write-Host "Total servers processed: $serverCount" -ForegroundColor White
Write-Host "Successful operations: $successCount" -ForegroundColor Green
Write-Host "  - Already in group: $alreadyExistsCount" -ForegroundColor Cyan
Write-Host "  - Newly added: $($successCount - $alreadyExistsCount)" -ForegroundColor Green
Write-Host "Failed operations: $failCount" -ForegroundColor Red
Write-Host "===================================" -ForegroundColor Magenta

Lessons Learned

  1. WinRM vs. PsExec: While PowerShell remoting via WinRM is Microsoft's preferred method, it requires proper configuration on all target servers. PsExec provides a reliable alternative for environments where WinRM isn't universally configured.
  2. Output Interpretation: Tools like PsExec can produce misleading output ("ERROR" followed by success indicators). Always parse the entire output for a complete understanding.
  3. Verification is Key: Always verify operations were successful, especially when working with permissions across multiple servers.
  4. Idempotent Operations: Design scripts to be idempotent - checking if the action is needed before attempting it saves time and prevents errors.
Previous Post Next Post

نموذج الاتصال