Tuesday, January 26, 2016

List account configured on logon of Windows Service - Powershell

Maintaining best practices on windows best thing, but when someone configures it incorrectly, it is hard to track those mis-configured item., you have to check through all the settings in documents and it is manually time consuming boring task. I had a scenario where other engineer used his username password on local services account in Services, and he left the organization or is on leave (password expired), causing  services to stop, and critical application is down in the absence of user, and you have to take all the heat.
Here is the script, helps to find or list accounts configured in the windows services. and are the following parameters to the scripts.
-ComputerName: If not specified default is localhost
-Service: if not specified default is lanmanserver, you have mention service name not display name

-Credential: Incase if remote computer in another domain or if you are not administrator you can use "-credential (get-credential)" to connect. otherwise for same domain this parameter doesn't required.
-Protocol: By default it uses legacy wmi dcom protocol to connect, there is another option wsman which use PSRemoting protocol.
 function Get-ServiceAccount {  
 <#  
  .Synopsis  
   Get the log on account configured in windows service.  
  .Description  
   The Get-ServiceAccount command collects log on account user configured in windows service. you will have to use servicename (not service display name) in the service parameter  
  .Example  
   Get-ServiceAccount  
   It will show log on account configured of the lanmanserver service.  
  .Example  
   "ServiceName" | Get-ServiceAccount  
   Cat c:\temp\Computerlist.txt | Get-ServiceAccount  
   Get-ServiceAccount is capable of taking output pipeline.  
   Get-ServiceAccount -Service wuauserv -Credential (Get-Credential) -ComputerName Server001  
   ∞ Server001 is pinging, attempting to connect...  
   PSComputerName : Server001  
   Name      : wuauserv  
   DisplayName  : Windows Update  
   StartMode   : Manual  
   State     : Running  
   Started    : True  
   StartName   : LocalSystem  
  .Example  
   Get-ServiceAccount -Service wuauserv -Credential (Get-Credential) -ComputerName Server001 -Protocol WSMAN   
   It collects the information using wsman protocol  
  .Example  
   "Server001", "server002", "Server003" | foreach {Get-ServiceAccount -Service someservice -ComputerName $_}  
   Get-Content -Path c:\temp\serverlist.txt | foreach {Get-ServiceAccount -Service someservice -ComputerName $_}  
   you can use it to featch information from multiple computers.  
  .Example  
   $cred = (Get-Crendential)  
   "Server001", "Server002" | foreach {Get-ServiceAccount -Computer $_ -Credential $cred -Service someservice}  
   Servers can be passed from array or files, and you can specify crendetials  
  .Parameter ComputerName  
   It is Alias to Name parameter  
   if kept blank by default will collect information about Localhost.  
  .Parameter Service  
   if kept blank by default will collect information about lanmanserver.  
  .Inputs  
   [string]  
  .OutPuts  
   Get-ServiceAccount -Service wuauserv -Credential (Get-Credential) -ComputerName 192.168.33.51  
   cmdlet Get-Credential at command pipeline position 1  
   Supply values for the following parameters:  
   ∞ 192.168.33.51 is pinging, attempting to connect...  
   PSComputerName : 192.168.33.51  
   Name      : wuauserv  
   DisplayName  : Windows Update  
   StartMode   : Manual  
   State     : Running  
   Started    : True  
   StartName   : LocalSystem  
  .Notes  
   NAME: Get-ServiceAccount  
   AUTHOR: Kunal Udapi  
   LASTEDIT: 26th August 2015  
   KEYWORDS: Service log on accounts  
  .Link  
   #Check Online version: Http://kunaludapi.blogspot.com   
   #Requires -Version 3.0  
  #>  
 #requires -Version 3   
 [CmdletBinding(SupportsShouldProcess)]  
 Param(  
   [Parameter(<#Mandatory=$true,#>Position=1,  
     ValueFromPipeline=$true,  
     ValueFromPipelineByPropertyName=$true)]  
   [AllowNull()]  
   [alias("ComputerName", "Computer")]  
   [string]$Name = $env:COMPUTERNAME,   
   [Parameter(Position=2)]  
   [AllowNull()]    
   [alias("ServiceName")]  
   [string]$Service = 'LanmanServer',  
   <#[Parameter(Mandatory=$true)]#$Credential#>  
   [System.Management.Automation.PSCredential]$Credential,  
   #[String]$CSVfile = "C:\Temp\ServiceDetails.csv",  
   $Protocol = 'DCOM'  
 ) #Param  
 Begin {  
   #$TempFolder = Split-Path $CSVfile  
   #if (-not (Test-Path $TempFolder)) {  
   #  [void](New-Item -Path $TempFolder -Force)  
   #} #if (-not (Test-Path $TempFolder)) {  
 #region Ping  
   Function Get-Ping {  
     Test-Connection -ComputerName $Name -Quiet -Count 2 -ErrorAction SilentlyContinue  
   } # Function Ping-Server  
 #endregion  
   $CIMoption = New-CimSessionOption -Protocol $protocol  
 } #Begin  
 Process {  
   $query = "Select * from Win32_Service Where Name = `'$service`'"  
   if ($(Get-Ping $Name) -eq $true) {  
     Write-Host "$([char]8734) $Name is pinging, attempting to connect..." -ForegroundColor Green  
     if ($Credential -eq $null) {  
       Try {  
         #$ServiceDetails = Get-WmiObject -Query $query -ComputerName $Name -ErrorAction SilentlyContinue  
         $CIMsession = New-CimSession -ComputerName $Name -SessionOption $CIMoption -ErrorAction SilentlyContinue  
         $ServiceDetails = Get-CimInstance -CimSession $CIMsession -Query $query  
       } #Try  
       Catch {  
         Write-Host "`t $([char]215) Server $Name cannot be contacted, skipped it" -ForegroundColor Red  
         Continue  
       } #Catch  
     } #if ($Credential -eq $null)  
     else {  
       Try {  
         #$ServiceDetail = Get-WmiObject -Query $query -ComputerName $Name -Credential $Credential -ErrorAction SilentlyContinue  
         $CIMsession = New-CimSession -ComputerName $Name -SessionOption $CIMoption -Credential $Credential -ErrorAction SilentlyContinue  
         $ServiceDetails = Get-CimInstance -CimSession $CIMsession -Query $query  
       } #Try  
       Catch {  
         Write-Host "`t $([char]215) Server $Name cannot be contacted, skipped it" -ForegroundColor Red  
         Continue  
       } #Catch  
     } #else ($Credential -eq $null)  
   } #if ($(Ping-Server $Name) -eq $true  
   else {  
     Write-Host "$([char]8734) $Name is not pinging, but Still trying to connect..." -ForegroundColor Yellow  
     if ($Credential -eq $null) {  
       Try {  
         #$ServiceDetail = Get-WmiObject -Query $query -ComputerName $Name -ErrorAction SilentlyContinue  
         $CIMsession = New-CimSession -ComputerName $Name -SessionOption $CIMoption -ErrorAction SilentlyContinue  
         $ServiceDetails = Get-CimInstance -CimSession $CIMsession -Query $query  
       } #Try  
       Catch {  
         Write-Host "`t $([char]215) Server $Name cannot be contacted, skipped it" -ForegroundColor Red  
         Continue  
       } #Catch  
     } #if ($Credential -eq $null)  
     else {  
       Try {  
         #$ServiceDetail = Get-WmiObject -Query $query -ComputerName $Name -Credential $Credential -ErrorAction SilentlyContinue  
         $CIMsession = New-CimSession -ComputerName $Name -SessionOption $CIMoption -Credential $Credential -ErrorAction SilentlyContinue  
         $ServiceDetails = Get-CimInstance -CimSession $CIMsession -Query $query  
       } #Try  
       Catch {  
         Write-Host "`t $([char]215) Server $Name cannot be contacted, skipped it" -ForegroundColor Red  
         Continue  
       } #Catch  
     } #else ($Credential -eq $null)  
   } #else ($(Ping-Server $Name) -eq $false)  
   if (-not ($ServiceDetails -eq $null)) {  
     $ServiceDetails | Select-Object PSComputerName, Name, DisplayName, StartMode, State, Started, StartName  
   } #if ($ServiceDetails -eq $null)  
   else {  
     Write-Host "`t $([char]215) Please check Server $Name manually" -ForegroundColor Red  
   } #else ($ServiceDetail -eq $null)  
 } #Process  
 End {  
 } #End  
 } $function  
 Get-ServiceAccount   
Using this script is fairly simple you can copy paste this code in Powershell profile, on how to use powershell profile you can check my another post here., In case if you don,t want to save it in profile, you can copy paste it in text file and rename extension to .ps1. and on the last line of .ps1 file put line Get-ServiceAccount to execute this function, and execute it in powershell doing dot sourcing file ie: .\script.ps1 (Before executing make sure you have run as administrator powershell and Set-ExecutionPolicy RemoteSigned (or bypass or unrestricted))

Here is the example how I can use this script for multiple servers
$cred = Get-Credential 
Get-Content -Path c:\temp\Serverslist.txt |  #Serverslist.txt contains list of servers
    foreach {Get-ServiceAccount -Credential $cred -ComputerName $_ -Service someservice} | 
        Export-Csv -NoTypeInformation -Path c:\temp\ServiceInfo.csv 
#You will need to make changes at the text marked in orange as per your need.

Above are some of the screenshots, checke out my next script changing username and password of the service logon. 
Other useful scripts:
Get members from Remote Groups

No comments: