none
Looking for a good way to store successful and failed processing in one place for logging

    General discussion

  • I am writing a script to reset passwords on a set of services on multiple servers. Ideally, the script will

    1. connect to the server
    2. validate the service exists
    3. if it exists check to see if it's disabled
    4. if it's not disabled, reset the password and restart the service
    5. if it is disabled, reset the password and not restart the service
    6. whether it succeeds or fails I need to log the results

    I have a series of built in checks, but, I am not sure how to handle the logging. My first thought it to write to an object for each result (all the errors and the one success).  So far I have the following (pretty long):

    <# .AUTHOR Will Steele (wlsteele@gmail.com) .NOTES To get parameters for the Win32_Service change method visit the following link: http://msdn.microsoft.com/en-us/library/windows/desktop/aa384901(v=vs.85).aspx This function passes $null for all but three parameters: Argument 1: DisplayName Argument 7: StartName Argument 8: StartPassword .LINKS #> #region Parameters [CmdletBinding()] param( [Parameter( Mandatory = $false )] [ValidateScript({Test-Path $_})] [String] $serverfile = 'C:\test\server.txt', [Parameter( Mandatory = $false )] [String[]] $servicedisplaynames = @("Print Spooler"),

    [Parameter( Mandatory = $false )] [String] $serviceaccount = 'someuser', [Parameter( Mandatory = $false )] [String] $servicepassword = 'somepassword', Parameter( )] [String] $logpath = 'C:\updateservicepassword.log' ) #endregion Parameters #region Configuration # Clear $Error variable Clear-Variable Error #endregion Configuration #region ScriptBody process { try { # Read server.txt to get a list of servernames. $servers = Get-Content -Path $serverfile -Encoding ASCII -ErrorAction Stop # Iterate over servers foreach($server in $servers) { # Test server connectivity if(Test-Connection -ComputerName $server -Count 1 -Quiet) { # Update multiple service passwords. foreach($servicedisplayname in $servicedisplaynames) { # Validate service is installed and stopped if($serviceinfo = (Get-WmiObject -Query "SELECT * FROM Win32_Service WHERE DisplayName = '$servicedisplayname'" -ComputerName $server -ErrorAction SilentlyContinue)) { # Output status to host Write-Output "$service is installed on $server. Checking startup state." switch($serviceinfo.StartMode) { "Disabled" { # Check service status - if stopped change password and do not start if($serviceinfo.Status -eq 'Stopped') { } # If started attempt to reset password and restart elseif($serviceinfo.Status -eq 'Started') { # Test to see if service settings match intended settings if(($serviceinfo.StartName -eq $serviceaccount) -and ($serviceinfo.StartPassword -eq $servicepassword)) { # Output status (matches desired settings) to pipeline Write-Output "$servicedisplayname on $server user and password match desired settings. Moving to next." } else { # Output status to host Write-Output "Attempting to update service ($servicedisplayname) password on $server." # Attempt to reset password on service Invoke-WmiMethod -ComputerName $server ` -Class Win32_Service ` -Name Change ` -ArgumentList @($servicedisplayname, $null, $null, $null, $null, $null, $serviceaccount, $servicepassword) # Validate service password has been updated if(Get-Service -DisplayName $servicedisplayname -ComputerName $server -ErrorAction SilentlyContinue).servicepassword -eq $servicepassword) { # Report successfully updated password Write-Output "The password ($servicepassword) for $service on $server password has been updated successfully." } else { # Report failed update Write-Output "The password ($servicepassword) for $service on $server was not updated." } } } # If status is neither started nor stopped report else { # Output status to host Write-Output "$service was neither running nor stopped. Not updated on $server." } } default { # Check service status - if stopped change password and do not start if($serviceinfo.Status -eq 'Stopped') { } # If started attempt to reset password and restart elseif($serviceinfo.Status -eq 'Started') { # Test to see if service settings match intended settings if(($serviceinfo.StartName -eq $serviceaccount) -and ($serviceinfo.StartPassword -eq $servicepassword)) { # Output status (matches desired settings) to pipeline Write-Output "$servicedisplayname on $server user and password match desired settings. Moving to next." } else { # Output status to host Write-Output "Attempting to update service ($servicedisplayname) password on $server." # Attempt to reset password on service Invoke-WmiMethod -ComputerName $server ` -Class Win32_Service ` -Name Change ` -ArgumentList @($servicedisplayname, $null, $null, $null, $null, $null, $serviceaccount, $servicepassword) # Validate service password has been updated if(Get-Service -DisplayName $servicedisplayname -ComputerName $server -ErrorAction SilentlyContinue).servicepassword -eq $servicepassword) { # Report successfully updated password Write-Output "The password ($servicepassword) for $service on $server password has been updated successfully. Attempting to restart service." # Attempt to restart service Restart-Service -DisplayName $servicedisplayname # Validate service started if((Get-Service -DisplayName $servicedisplayname).Status -eq 'Running') { Write-Output "The service ($servicedisplayname) was restarted on $server." } else { Write-Output "The service ($servicedisplayname) was not restarted on $server." } } else { # Report failed update Write-Output "The password ($servicepassword) for $service on $server was not updated." } } } # If status is neither started nor stopped report else { # Output status to host Write-Output "$service was neither running nor stopped. Not updated on $server." } } } } elseif($serviceinfo -eq $null) { Write-Output "$service was not installed on $server." } } } else { Write-Output "$server is not accessible." } } } catch { Write-Error $_ } }


    Saturday, March 31, 2012 3:13 AM

All replies

  • Instead of specific suggestions, I am going to criticise you script in terms of design:

    Ed Wilson recently gave a list of do's and dont's for the scripting games.  One of them was "Don't use Write-Host".  I assume the same applies to Write-Output, because what he was getting at was rather collect the information in an object, and then output the object at the end.

    Because of the way you are writing to console, this makes it difficult and inelegant to add logging to file.  I suggest that you, as you said, write to an object (array comes to mind) instead of to the screen.


    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    Saturday, March 31, 2012 4:21 AM