2010-01-15

A bit of housekeeping – Powershell

I have been busy with using Powershell in these past few days.

I would like to share with you two of the scripts that I used lately. They were both used because of a password change that was made on a service account.

Now the thing about service accounts in Windows 2003 is, they are good, they need elevated privileges in some cases, and since the account is used for the specific purpose then you know that you have to change it once in a while and you know where. Problem is though unless you catch them all – and someone – somewhere  did not update the password somewhere, then you will start having issues with account lockouts.

First is to get all the services from all the computers in my OU, and change the password

   1: $logfile = "c:\temp\results.log"
   2: $serviceaccount = "svcmacct"
   3: $password = ""
   4:  
   5: $serviceslist = Get-QADComputer -SearchRoot "OU=Public Servers,DC=maishsk,DC=local" -OsName window* -searchscope "subtree" -ErrorAction SilentlyContinue | ` 
   6: ForEach-Object {
   7:     (Get-WmiObject -Class Win32_Service -ComputerName $_.Name -ErrorAction  `
   8:             SilentlyContinue | where {
   9:                 $_.'StartName' -like $serviceaccount
  10:             }
  11:     ) 
  12: }
  13:  
  14: [System.Reflection.Assembly]::LoadWithPartialName('system.serviceprocess')
  15:  
  17:     ForEach ($line in $serviceslist) {
  18:         Write-Host Processing $line.Systemname
  19:         $service = Get-WmiObject win32_Service -ComputerName $line.Systemname -Filter "Name='$($line.Name)'"
  20:         Write-host Stopping Service $line.Name
  21:         (new-object System.ServiceProcess.ServiceController($($line.Name),$($line.Systemname))).Stop()
  22:         (new-object System.ServiceProcess.ServiceController($($line.Name),$($line.Systemname))).WaitForStatus('Stopped',(new-timespan -seconds 90)) 
  23:         if ($? -eq $true) {
  24:         $service.Change($null ,$null ,$null ,$null ,$null ,$null , $serviceAccount, $password )
  25:         Write-host Starting Service $line.Name
  26:         (new-object System.ServiceProcess.ServiceController($($line.Name),$($line.Systemname))).Start()
  27:         (new-object System.ServiceProcess.ServiceController($($line.Name),$($line.Systemname))).WaitForStatus('Running',(new-timespan -seconds 40)) 
  28:         write-output $(get-date -DisplayHint time)` --` Service` $($line.Caption)` on` $($line.SystemName)` has` been` updated` and` restarted >> $logfile
  29:         } else {
  30:         write-output $(get-date -DisplayHint time)` --` Service` $($line.Caption)` on` $($line.SystemName)` update` failed >> $logfile
  31:         }
  32: }

Line 5 – get all the computers in the desired OU and get the services.

Line 22 – Here is a wait statement for the service to stop, otherwise this will cause issues with the rest of script. Please remember that the time span is there to ensure that if something goes wrong – then you script will continue, otherwise you will have to close the shell window - Ctrl+C will not work.

Line 28 – logs the results to a file including a time stamp.

 

Second script was to change the passwords for all the scheduled tasks using this same service account

   1:  
   2: $mycomps = Get-QADComputer -SearchRoot "maishsk.local/Public Servers" -SearchScope Subtree -SizeLimit 0 
   3:  
   4: $logfile = "c:\temp\tasklist.csv"
   5: $results = "c:\temp\results.log"
   6:  
   7: $report = @()
   8: $mycomps | ForEach-Object -ErrorAction SilentlyContinue {
   9:     schtasks.exe /s $_.Name /query /v /fo csv >> $logfile 2>>c:\temp\errors.txt
  10:     }
  11: $report = import-Csv $logfile
  12:  
  13: ##Get all tasks that are run under a certain user
  14: $svcaccount = Read-Host "Please Enter Service account Name (Domain\Username)"
  15: $mytasks = ""
  16: $mytasks = $report | Where-Object {($_."Run As User" -like $svcaccount) -and ($_."Next Run Time" -ne "Disabled")} | select Hostname, TaskName
  17: #Remove unwanted Characters
  18: $mytasks | ForEach-Object {
  19:     $_.TaskName = ($_.TaskName).Trimstart("\")
  20:     }
  21:  
  22: ##Change credentials for the task
  23:  
  24: foreach ($task in $mytasks) {
  25:     schtasks.exe /change /S $($task.HostName) /TN "$($task.Taskname)" /RP $password >> $results 2>>c:\temp\errors.txt
  26: }

Line 9 – schtasks.exe is the was I decided to go to get the info – I could not find anything else in Powershell that would extract the info.

Line 18-19 – the output came back with an extra “\” in the beginning – I used the Trimstart method to remove it.

Line 25 – This actually took a while to find the exact syntax that I was looking for.

If you have any comments or  improvements I would appreciate you input.