ES1_Services.psm1
<# .NOTES =========================================================================== Copyright � 2018 Dell Inc. or its subsidiaries. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 =========================================================================== THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. IF THIS CODE AND INFORMATION IS MODIFIED, THE ENTIRE RISK OF USE OR RESULTS IN CONNECTION WITH THE USE OF THIS CODE AND INFORMATION REMAINS WITH THE USER. .DESCRIPTION Functions for managing SourceOne Services #> #requires -Version 2 $SvcShow = 1 $SvcStart = 2 $SvcStop = 3 $svcRestart = 4 $svcPause = 5 $svcResume = 6 $WaitTime = '00:00:30' $WaitSeconds = 50 Add-Type -TypeDefinition @" public enum ServiceAction{ Show, Start, Stop, Restart, Pause, Resume } "@ function Get-ES1Services { <# .SYNOPSIS Get a list of SourceOne Services on the specified Server(s) .DESCRIPTION Get a list of SourceOne Services on the specified Server(s) .PARAMETER ComputerName Specifies the computer against which you want to run the management operation. The Value can be a fully qualified domain Name, a NetBIOS Name, or an IP address. Use the local computer Name, use localhost, or use a dot (.) to specify the local computer. The local computer is the default. When the remote computer is in a different domain from the user, you must use a fully qualified domain Name. This parameter can also be piped to the cmdlet. .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. Type a user Name, such as "User01", "Domain01\User01", or user@Contoso.com. Or, enter a PSCredential object, such as an object that is returned by the Get-Credential cmdlet. When you Type a user Name, you will be prompted for a Password. .EXAMPLE Get-ES1Services Status Name DisplayName ------ ---- ----------- Running ES1AddressResol... EMC SourceOne Address Resolution Running ES1InPlaceMigSe... EMC SourceOne Inplace Migration Running ExJobDispatcher EMC SourceOne Job Dispatcher #> [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string[]]$ComputerName = $env:computername, $Credential = $remCreds ) $es1Services = @() # # Process each machine one at a time so we can handle the errors nicely... # $cntIds=$ComputerName.Count $i=0 foreach($computer in $ComputerName) { [int]$dispCnt = ($i+1) Write-Progress -id 1 -Activity "Getting SourceOne Services " -Status "Number of SourceOne Machines: $cntIds" -percentcomplete (($i/$cntIds)*100) -Currentoperation "Processing Machine: $computer ($dispCnt)" $i++ try { $es1Services += get-service -displayname '*emc sourceone*' -ComputerName $computer -ErrorAction SilentlyContinue -ErrorVariable gserror } catch { Write-Host "Error accessing server: $($computer). Make sure the machine is up and reachable" -ForegroundColor Red Write-Host $gserror.Message -ForegroundColor Red # create a fake object to return so all machines are in the list $errobj = New-Object System.ServiceProcess.ServiceController $errobj.MachineName = $computer # $errobj.ServiceName="ERROR" $errobj.DisplayName="ERROR accessing server !" $es1Services +=$errobj } } $es1Services } function Show-ES1Services { <# .SYNOPSIS Displays a list of SourceOne Services on the specified Server(s) .DESCRIPTION Displays a list of SourceOne Services on the specified Server(s) .PARAMETER ComputerName Specifies the computer against which you want to run the management operation. The Value can be a fully qualified domain Name, a NetBIOS Name, or an IP address. Use the local computer Name, use localhost, or use a dot (.) to specify the local computer. The local computer is the default. When the remote computer is in a different domain from the user, you must use a fully qualified domain Name. This parameter can also be piped to the cmdlet. .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. Type a user Name, such as "User01", "Domain01\User01", or user@Contoso.com. Or, enter a PSCredential object, such as an object that is returned by the Get-Credential cmdlet. When you Type a user Name, you will be prompted for a Password. .EXAMPLE Show-ES1Services displayname Name State systemname ----------- ---- ----- ---------- EMC SourceOne Address Resolution ES1AddressResolutionService Running IPMWORKER3 EMC SourceOne Inplace Migration ES1InPlaceMigService Running IPMWORKER3 EMC SourceOne Job Dispatcher ExJobDispatcher Running IPMWORKER3 #> [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string[]]$ComputerName = $env:computername, $Credential = $remCreds ) try { $machineServices = Get-ES1Services $ComputerName $Credential $machineServices| sort machinename | select-object MachineName,DisplayName,Name,Status | Format-Table -AutoSize #| Out-String -Width 10000 } catch { Write-Error $_ } } function Set-ES1WaitTimeforServices { <# .SYNOPSIS Update global session variable $WaitSeconds used to manage services .DESCRIPTION Update global session variable $WaitSeconds used to manage services .PARAMETER seconds provide the number of seconds between 1 and 60 .EXAMPLE #> [CmdletBinding()] param ( [int] $seconds ) if ($seconds -ge 0 -and $seconds -le 60) { Write-Verbose "current value $WaitSeconds" $Script:WaitSeconds = $seconds Write-Output "Seconds to wait for service functions updated to $Script:WaitSeconds" } else { Write-Host "Wait time must be between 0 and 60" } } <# .SYNOPSIS Gets a list of System.ServiceProcess.ServiceController objects for all SourceOne services on all SourceOne machines .DESCRIPTION Uses $s1Servers list to query all servers for status of s1 services .OUTPUT System.ServiceProcess.ServiceController .EXAMPLE Get-AllES1Services Status Name DisplayName ------ ---- ----------- Running ES1AddressResol... EMC SourceOne Address Resolution Running ES1InPlaceMigSe... EMC SourceOne Inplace Migration Running ExAsAdmin EMC SourceOne Administrator Running ExAsArchive EMC SourceOne Archive Running ExAsIndex EMC SourceOne Indexer Running ExAsQuery EMC SourceOne Query Running ExJobDispatcher EMC SourceOne Job Dispatcher Stopped ES1AddressResol... EMC SourceOne Address Resolution Stopped ExAddressCacheS... EMC SourceOne Address Cache Stopped ExAsAdmin EMC SourceOne Administrator Stopped ExAsArchive EMC SourceOne Archive #> function Get-AllES1Services { [CmdletBinding()] Param() if ($s1servers.count -eq 0) { # This will set the "global" $s1servers, so throw the local output away Get-ES1servers > $null } Get-ES1Services $s1Servers } <# .SYNOPSIS Starts all SourceOne services on all SourceOne machines .DESCRIPTION Uses $s1Servers list to query all servers for status of s1 services .EXAMPLE Start-AllES1Services Status Name DisplayName ------ ---- ----------- Running ES1AddressResol... EMC SourceOne Address Resolution Running ES1InPlaceMigSe... EMC SourceOne Inplace Migration Running ExAsAdmin EMC SourceOne Administrator Running ExAsArchive EMC SourceOne Archive Running ExAsIndex EMC SourceOne Indexer Running ExAsQuery EMC SourceOne Query Running ExJobDispatcher EMC SourceOne Job Dispatcher Stopped ES1AddressResol... EMC SourceOne Address Resolution Stopped ExAddressCacheS... EMC SourceOne Address Cache Stopped ExAsAdmin EMC SourceOne Administrator Stopped ExAsArchive EMC SourceOne Archive #> function Start-AllES1Services { [CmdletBinding()] Param() if ($s1servers.count -eq 0) { # This will set the "global" $s1servers, so throw the local output away get-ES1servers > $null } Start-ES1Services $s1Servers } <# .SYNOPSIS Stops all SourceOne services on all known SourceOne machines .DESCRIPTION Stops all SourceOne services on all known SourceOne machines Uses $s1Servers list to query all servers for status of s1 services .EXAMPLE Stop-AllES1Services Status Name DisplayName ------ ---- ----------- Running ES1AddressResol... EMC SourceOne Address Resolution Running ES1InPlaceMigSe... EMC SourceOne Inplace Migration Running ExAsAdmin EMC SourceOne Administrator Running ExAsArchive EMC SourceOne Archive Running ExAsIndex EMC SourceOne Indexer Running ExAsQuery EMC SourceOne Query Running ExJobDispatcher EMC SourceOne Job Dispatcher Stopped ES1AddressResol... EMC SourceOne Address Resolution Stopped ExAddressCacheS... EMC SourceOne Address Cache Stopped ExAsAdmin EMC SourceOne Administrator Stopped ExAsArchive EMC SourceOne Archive #> function Stop-AllES1Services { [CmdletBinding()] Param() if ($s1servers.count -eq 0) { # This will set the "global" $s1servers, so throw the local output away get-ES1servers > $null } Stop-ES1Services $s1Servers } function Show-AllES1Services { <# .SYNOPSIS Displays the status of all SourceOne Services on all known machines .DESCRIPTION Displays the status of all SourceOne Services on all known machines .EXAMPLE Show-AllES1Services #> [CmdletBinding()] param() $allServices = get-AllES1Services $allServices| sort machinename | ` select-object MachineName,DisplayName,Name,Status | Format-Table -AutoSize #| Out-String -Width 10000 } <# .SYNOPSIS Changes the state of all the "EMC SourceOne*" services on the specified machine(s) .DESCRIPTION Changes the state of all the "EMC SourceOne*" services on the specified machine(s) Guts of (almost) all the other SourceOne service functions .PARAMETER Computername Default to localhost, server name string or array of server names .PARAMETER Action [ServiceAction] enum .PARAMETER Wait Wait until the desired state is reached. .EXAMPLE Update-ES1Services -Action Stop .EXAMPLE Update-ES1Services -ComputerName ArchiveServ1 -Action Stop #> function Update-ES1Services { [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string[]]$ComputerName = 'localhost', [ServiceAction] $Action = [ServiceAction]::Show, $Credential = $remCreds, [bool]$Wait = $true ) # # Process each machine one at a time so we can handle the errors nicely... # $cntIds=$ComputerName.Count $i=0 foreach ($computer in $ComputerName) { [int]$dispCnt = ($i+1) Write-Progress -id 1 -Activity "Managing Services State Change " -Status "Number of SourceOne Machines: $cntIds" -percentcomplete (($i/$cntIds)*100) -Currentoperation "Processing Machine: $computer ($dispCnt)" $i++ try { $es1Services = get-service -displayname '*emc sourceone*' -ComputerName $computer -ErrorAction SilentlyContinue -ErrorVariable gserror $WaitStr = '' $svcCount=$es1Services.Count $j=0 foreach ($service in $es1Services) { Write-Verbose "$($service.name ) in state $($service.Status)" [int]$dispSvcCnt = ($j+1) $j++ Write-Progress -id 2 -parentId 1 -Activity "Changing Services on $($computer)" -Status "Number of Services: $svcCount " -percentcomplete (($j/$svcCount)*100) -Currentoperation "Service : $($service.Name) ($dispSvcCnt)" if ($Action -eq [ServiceAction]::Show) { Write-Error "Unsupported feature !" return } try { # do a refresh because stopping a service with dependencies will stop those dependencies too # before we get to them $service.Refresh() Write-Verbose "Refreshed returned state $($service.Status)" switch ($Action) { ([ServiceAction]::Stop) { $WaitStr = 'Stopped' if (($service.Status -ne "Stopped") -and ($service.Status -ne "StopPending")) { $service.Stop() } else{ Write-Verbose " Already in stopped or stoppending" } break } ([ServiceAction]::Start) { $WaitStr = 'Running' $service.Start() break } ([ServiceAction]::Pause) { $WaitStr = 'Paused' $service.Pause() break } #$SvcResume {$hr = $service.ResumeService(); $WaitStr = 'Running'} } } catch { #service control function above will fail if already in the state desired.... Write-Error $_ } $service.Refresh() $hr = $service.status write-verbose "WaitStr: $($WaitStr) WaitTime: $($waittime)" write-verbose "$($service.name) on $($service.machinename) is $($hr)" if ($hr -ne $WaitStr) { try { $svc = Get-Service -ComputerName $service.machinename -name $service.name $svc.WaitForStatus($WaitStr,$waittime) $hr = $svc.status } catch { Write-Host "" } } if ($hr -ne $WaitStr) { write-host "after waiting $waittime seconds, $($service.name) on $($service.machinename) failed change to $waitstr" } } Write-Progress -id 2 -parentId 1 -Activity "Changing Services on $($computer)" -Completed -Status "Done" } catch { Write-Host "Error accessing server: $($computer). Make sure the machine is up and reachable" -ForegroundColor Red Write-Host $gserror.Message -ForegroundColor Red } } } <# .SYNOPSIS Starts the SourceOne services on the machine or machines specified .DESCRIPTION Starts the SourceOne services on the machine or machines specified .PARAMETER ComputerName The name of target server or array of servers .PARAMETER Wait Wait until the desired state is reached. .EXAMPLE Start-ES1Services Master .EXAMPLE Start-ES1Services Master WebServer #> function Start-ES1Services { [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string[]]$ComputerName = 'localhost', $Credential = $remCreds, [bool]$Wait = $true ) $s = Update-ES1Services -ComputerName $ComputerName -action Start -Credential $Credential -wait $Wait Show-ES1Services $ComputerName } <# .SYNOPSIS Performs a "Stop" and then "Start" on all SourceOne services on the specified machine(s) .DESCRIPTION Performs a "Stop" and then "Start" on all SourceOne services on the specified machine(s) .PARAMETER ComputerName The name of target server or array of servers .PARAMETER Wait Wait until the desired state is reached. .EXAMPLE Restart-ES1Services Master .EXAMPLE Restart-ES1Services Master WebServer #> function Restart-ES1Services { [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string[]]$ComputerName = 'localhost', $Credential = $remCreds, [bool]$Wait = $true ) $s = Update-es1Services -ComputerName $ComputerName -action Stop -Credential $Credential -wait $true $s = Update-es1Services -ComputerName $ComputerName -action Start -Credential $Credential -wait $Wait Show-ES1Services $ComputerName } # The only s1 service that appears to pause is DCWorkerService function Pause-ES1Services { <# .SYNOPSIS Pauses SourceOne service. Not all SourceOne services support this state. .DESCRIPTION Pauses SourceOne service. Not all SourceOne services support this state. The only s1 service that appears to pause is DCWorkerService .PARAMETER ComputerName Specifies the computer against which you want to run the management operation. The Value can be a fully qualified domain Name, a NetBIOS Name, or an IP address. Use the local computer Name, use localhost, or use a dot (.) to specify the local computer. The local computer is the default. When the remote computer is in a different domain from the user, you must use a fully qualified domain Name. This parameter can also be piped to the cmdlet. .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. Type a user Name, such as "User01", "Domain01\User01", or user@Contoso.com. Or, enter a PSCredential object, such as an object that is returned by the Get-Credential cmdlet. When you Type a user Name, you will be prompted for a Password. .PARAMETER Wait Wait until the desired state is reached. #> [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string[]]$ComputerName = 'localhost', $Credential = $remCreds, [bool]$Wait = $true ) $s = Update-es1Services -ComputerName $ComputerName -action Pause -Credential $Credential -wait $Wait Show-es1Services $ComputerName } function Resume-ES1Services { <# .SYNOPSIS Resumes SourceOne service. Not all SourceOne services support this state. .DESCRIPTION Resumes SourceOne service. Not all SourceOne services support this state. .PARAMETER ComputerName .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. Type a user Name, such as "User01", "Domain01\User01", or user@Contoso.com. Or, enter a PSCredential object, such as an object that is returned by the Get-Credential cmdlet. When you Type a user Name, you will be prompted for a Password. .PARAMETER Wait Wait until the desired state is reached. #> [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string[]]$ComputerName = 'localhost', $Credential = $remCreds, $Wait = $true ) $s = Update-ES1Services -ComputerName $ComputerName -action Resume -Credential $Credential -wait $Wait Show-es1Services $ComputerName } <# .SYNOPSIS Stops SourceOne services on a specific machine(s) .DESCRIPTION Stops SourceOne services on a specific machine(s) .PARAMETER ComputerName The name of target server or array of servers .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. Type a user Name, such as "User01", "Domain01\User01", or user@Contoso.com. Or, enter a PSCredential object, such as an object that is returned by the Get-Credential cmdlet. When you Type a user Name, you will be prompted for a Password. .PARAMETER Wait Wait until the desired state is reached. .EXAMPLE Stop-ES1Services Master .EXAMPLE Stop-ES1Services Master WebServer #> function Stop-ES1Services { [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string[]]$ComputerName = 'localhost', $Credential = $remCreds, [bool]$Wait = $true ) # If we are passed credentials just use them # If not see if we have Admin privs and if we get new privs use those if (-not $Credential) { $isAdmin = Test-IsAdmin if ( -not $isAdmin ) { return } } $s = Update-ES1Services -ComputerName $ComputerName -action Stop -Credential $Credential -wait $wait Show-es1Services $ComputerName } function Get-S1ServicesByAccount <# .SYNOPSIS Get the services which use the specified account (s1 service account) as the user .DESCRIPTION Get the services which use the specified account (s1 service account) as the user .PARAMETER ComputerName Specifies the computer against which you want to run the management operation. The Value can be a fully qualified domain Name, a NetBIOS Name, or an IP address. Use the local computer Name, use localhost, or use a dot (.) to specify the local computer. The local computer is the default. When the remote computer is in a different domain from the user, you must use a fully qualified domain Name. This parameter can also be piped to the cmdlet. .PARAMETER s1acct SourceOne account .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. Type a user Name, such as "User01", "Domain01\User01", or user@Contoso.com. Or, enter a PSCredential object, such as an object that is returned by the Get-Credential cmdlet. When you Type a user Name, you will be prompted for a Password. .EXAMPLE #> { [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string[]]$ComputerName = $env:computername, $s1acct = $env:USERNAME, $Credential = $remCreds ) $gservicelist=@() $filterTemplate = "startname like '%xxxx%'" $filter = $filterTemplate.Replace("xxxx",$s1acct) try { if ($ComputerName -eq $localhost) { write-debug "$ComputerName is localhost" $gservicelist = gwmi -class win32_service -filter $filter -ErrorAction Stop } else { write-debug "$ComputerName is remote" $gservicelist = gwmi -class win32_service -filter $filter -ComputerName $ComputerName -ErrorAction Stop } } catch { throw $_ } $gservicelist } <# .SYNOPSIS Shows a list of the services which use the specified account (s1 service account) as the user on the given Computer .DESCRIPTION Shows a list of the services which use the specified account (s1 service account) as the user on the given Computer .PARAMETER ComputerName Specifies the computer against which you want to run the management operation. The Value can be a fully qualified domain Name, a NetBIOS Name, or an IP address. Use the local computer Name, use localhost, or use a dot (.) to specify the local computer. The local computer is the default. When the remote computer is in a different domain from the user, you must use a fully qualified domain Name. This parameter can also be piped to the cmdlet. .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. Type a user Name, such as "User01", "Domain01\User01", or user@Contoso.com. Or, enter a PSCredential object, such as an object that is returned by the Get-Credential cmdlet. When you Type a user Name, you will be prompted for a Password. .EXAMPLE #> function Show-S1ServicesByAccount { [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string]$ComputerName = $env:computername, $s1acct = $env:USERNAME, $Credential = $remCreds ) try { $results = Get-S1ServicesByAccount -ComputerName $ComputerName -s1acct $s1acct -Credential $remCreds } catch { Write-Warning "Error getting services from machine: $($ComputerName). Make sure the machine is running and reachable." # create a fake object to return so all machines are in the list $props = @{'SystemName'=$ComputerName;'Name'='';'State'='Cannot access server';'Status'=$_.Exception.Message} $results = New-object -TypeName PSObject -Prop $props } $results | select-object SystemName,Name,State,Status | Format-Table -AutoSize | Out-String -Width 10000 } function Show-AllS1ServicesByAccount <# .SYNOPSIS Shows a list of the services which use the specified account (s1 service account) as the user on all known S1 machines .DESCRIPTION Shows a list of the services which use the specified account (s1 service account) as the user on all known S1 machines .PARAMETER s1acct .EXAMPLE #> { [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] $s1acct = $env:USERNAME, $Credential = $remCreds ) if ($s1servers.count -eq 0) { # This will set the "global" $s1servers, so throw the local output away get-ES1servers > $null } foreach ($server in $s1servers) { try { $results = Get-S1ServicesByAccount -ComputerName $server -s1acct $s1acct -Credential $remCreds } catch { Write-Warning "Error getting services from machine: $($server). Make sure the machine is running and reachable." # create a fake object to return so all machines are in the list $props = @{'SystemName'=$server;'Name'='';'State'='Cannot access server';'Status'=$_.Exception.Message} $results = New-object -TypeName PSObject -Prop $props } $results | select-object SystemName,Name,State,Status | Format-Table -AutoSize | Out-String -Width 10000 } } <# .SYNOPSIS Updates the password for all S1 services on the specified machine(s). .DESCRIPTION Updates the password for all S1 services on the specified machine(s). This does not perform a password change for the account itself. This only sets the password for the service to run with. .PARAMETER ComputerName Specifies the computer against which you want to run the management operation. The Value can be a fully qualified domain Name, a NetBIOS Name, or an IP address. Use the local computer Name, use localhost, or use a dot (.) to specify the local computer. The local computer is the default. When the remote computer is in a different domain from the user, you must use a fully qualified domain Name. This parameter can also be piped to the cmdlet. .PARAMETER s1acct SourceOne service account name .PARAMETER Password System.Security.SecureString containing the password to use. If not supplied you will be prompted and input will be masked. .PARAMETER timeout The number of seconds to wait for services to stop or start. The default is 10 seconds .PARAMETER Credential (UNUSED) Specifies a user account that has permission to perform this action. The default is the current user. Type a user Name, such as "User01", "Domain01\User01", or user@Contoso.com. Or, enter a PSCredential object, such as an object that is returned by the Get-Credential cmdlet. When you Type a user Name, you will be prompted for a Password. .EXAMPLE #> function Update-S1ServicesAccountInfo { [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string[]]$ComputerName = $env:computername, [string]$s1acct = $env:USERNAME, [Parameter(Mandatory=$true, HelpMessage='Enter the Service Account Password')] [ValidateNotNullOrEmpty()] [System.Security.SecureString] $Password, [int]$timeout = 10, $Credential = $remCreds ) if (-not (Test-ADCredential -username $s1acct -password $Password)) { Write-Error "Password provided is not the current or correct password !" return } $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password) $s1pw = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr) $results=@() $waitRet=$false # # Process each machine one at a time so we can handle the errors nicely... # $cntIds=$ComputerName.Count $i=0 foreach ($computer in $ComputerName) { [int]$dispCnt = ($i+1) Write-Progress -id 1 -Activity "Processing Service Password Update" -Status "Number of SourceOne Machines: $cntIds" -percentcomplete (($i/$cntIds)*100) -Currentoperation "Processing Machine: $computer ($dispCnt)" $i++ $services=@() try { $services = Get-S1ServicesByAccount -ComputerName $computer -s1acct $s1acct -Credential $remCreds } catch { Write-Error "Error getting services from machine: $($computer). Make sure the machine is running and reachable." $props = @{'SystemName'=$computer;'ServiceName'='NA';'StopStatus'=$_.Exception.Message;'ChangeStatus'='';'StartStatus'=''} $MachineResults = New-object -TypeName PSObject -Prop $props $results +=$MachineResults continue } $svcCount=$services.Count $j=0 foreach ($svc in $services) { [int]$dispSvcCnt = ($j+1) $j++ # Get dependent services and stop those first... $depends=Get-WMIObject -ComputerName $computer -Query "Associators of {Win32_Service.Name='$($svc.name)'} Where AssocClass=Win32_DependentService Role=Antecedent" Write-Progress -id 2 -parentId 1 -Activity "Updating Service Passwords on $($computer)" -Status "Number of Services: $svcCount " -percentcomplete (($j/$svcCount)*100) -Currentoperation "Service : $($svc.Name) ($dispSvcCnt)" Write-Verbose "Stopping service $($svc.name) on server $($svc.systemname) " # # This whole stop start process does NOT take into account the current state of the service # If the services is already stopped, it will blindly be started below. Maybe thats not a good # thing (??) if ($depends.Count -gt 0) { foreach ($depSvc in $depends) { if (($depSvc.State -ne 'Stopped' ) -and ($depSvc.State -ne 'StopPending' )) { Write-Verbose "Stopping Dependent Service $($depSvc.name) on server $($depSvc.systemname) " $depret = $depSvc.StopService() $waitRet=WaitForService $depSvc.name 'stopped' $timeout $computer } } } $ret = $svc.StopService() $waitRet=WaitForService $svc.name 'stopped' $timeout $computer $props = @{'SystemName'=$computer;'ServiceName'=$svc.Name;'StopStatus'=$waitRet;'ChangeStatus'='';'StartStatus'=''} $MachineResults = New-object -TypeName PSObject -Prop $props Write-Verbose "modifying service $($svc.name) on server $($svc.systemname) " $changeStatus = $svc.Change($null,$null,$null,$null,$null,$null,$null,$s1pw,$null,$null,$null) if ($changeStatus.ReturnValue -eq "0") { write-host "Server: $($svc.systemname) Password changed for service $($svc.name)" $MachineResults.ChangeStatus='Success' } else { write-error "Server: $($svc.systemname) Password change FAILED for service $($svc.name), Error Code=$($changeStatus.ReturnValue)" $MachineResults.ChangeStatus=$changeStatus.ReturnValue } Write-Verbose "starting service $($svc.name) on $($svc.systemname) " $ret = $svc.StartService() # only wait if startservice was "accepted" if ($ret.ReturnValue -eq 0) { $waitRet=WaitForService $svc.name 'running' $timeout $computer $MachineResults.StartStatus=$waitRet } elseif ($ret.ReturnValue -eq 15) { Write-Error "Authentication failure starting service: $($svc.name) !`nWrong password supplied !" $MachineResults.StartStatus='Authentication failure starting service!' } else { $MachineResults.StartStatus=$ret.ReturnValue Write-Error "Unexpected error starting service $($svc.name) ! StartService returned error $($ret.ReturnValue) !" } $results +=$MachineResults } Write-Progress -id 2 -parentId 1 -Activity "Updating Service Passwords on $($computer)" -Completed -Status "Done" } Write-Progress -id 1 -Activity "Updating Passwords " -Completed -Status "Done" $results | select-object SystemName,ServiceName,StopStatus,ChangeStatus,StartStatus } <# .SYNOPSIS Updates the password for all S1 services on all known SourceOne machines. .DESCRIPTION Updates the password for all S1 services on all known SourceOne machines. Not all machines running SourceOne services are known to the SourceOne systems. .PARAMETER s1acct SourceOne service account name .PARAMETER timeout The number of seconds to wait for services to stop or start. The default is 10 seconds .PARAMETER Credential (UNUSED) Specifies a user account that has permission to perform this action. The default is the current user. Type a user Name, such as "User01", "Domain01\User01", or user@Contoso.com. Or, enter a PSCredential object, such as an object that is returned by the Get-Credential cmdlet. When you Type a user Name, you will be prompted for a Password. .EXAMPLE #> function Update-AllS1ServicesAccountInfo { [CmdletBinding()] param ( [Parameter( ValueFromPipeLine=$true, ValueFromPipeLineByPropertyName=$true)] [string]$s1acct = $env:USERNAME, [int]$timeout = 10, $Credential = $remCreds ) $isAdmin = Test-IsAdmin if ( -not $isAdmin) { return } Write-Host "" $newpassword = read-host -Prompt "Enter the password for $($s1acct)" -AsSecureString Write-Host "" if ($s1servers.count -eq 0) { # This will set the "global" $s1servers, so throw the local output away get-ES1servers > $null } $updResults= Update-S1ServicesAccountInfo -s1acct $s1acct -Password $newpassword -ComputerName $s1servers $updResults | sort SystemName | Format-Table -AutoSize |Out-String -Width 10000 #Show-AllS1ServicesByAccount -s1acct $s1acct } function WaitForService ([string] $svc,[string] $command,[int] $secs,[string]$Server = $env:COMPUTERNAME) <# .SYNOPSIS Internal use .DESCRIPTION Internal use #> { $ret = $false $x = get-service $svc -computername $Server -ErrorAction SilentlyContinue $Done = $false $secs-- if ($secs -le 0 ) { $secs = 0 } while (!$Done) { if ($x.status -ne $command) { Sleep -Seconds 1 if ($secs-- -eq 0) { break } $x.Refresh() #$x = get-service $svc -computername $Server -ErrorAction SilentlyContinue write-debug "Waiting for $svc to be $command" } else { $state = $x.status Write-Verbose "$svc on $Server is $state" $Done = $true $ret = $true break } } if (!$Done) { write-host "****Timer has expired waiting for $($svc) on $($Server) to be $($command)" } $ret } function Test-S1ServiceExists ([string] $svc,$Server = $env:COMPUTERNAME) <# .SYNOPSIS Test if a specific service present on the specified computer .DESCRIPTION Test if a specific service present on the specified computer .PARAMETER .EXAMPLE TBD #> { $x = get-service $svc -computername $server -ErrorAction SilentlyContinue if ($x -ne $null) { return $true } else { return $false } } New-Alias Get-AllS1Services Get-AllES1Services New-Alias Get-S1Services Get-ES1Services New-Alias Start-S1Services Start-ES1Services New-Alias Start-AllS1Services Start-AllES1Services New-Alias Stop-S1Services Stop-ES1Services New-Alias Stop-AllS1Services Stop-AllES1Services New-Alias ReStart-S1Services ReStart-ES1Services New-Alias Get-ES1ServicesByAccount Get-S1ServicesByAccount New-Alias Show-ES1ServicesByAccount Show-S1ServicesByAccount New-Alias Show-AllES1ServicesByAccount Show-AllS1ServicesByAccount New-Alias Update-ES1ServicesAccountInfo Update-S1ServicesAccountInfo New-Alias Update-AllES1ServicesAccountInfo Update-AllS1ServicesAccountInfo New-Alias Test-ES1ServiceExists Test-S1ServiceExists Export-ModuleMember -Function *-* -Alias * |