Auto fix services after comparing before and after reboot

I succeeded in comparing the services before and after reboot, how would i auto fix it. If someone can help.

Basically, i want every service which was Running before, should be running now.

Since now I have got this :

$compareobject = Compare-Object -ReferenceObject $(Get-Content C:\before.txt) -DifferenceObject $(Get-Content C:\after.txt)|
Where-Object {$.SideIndicator -eq “=>”}| ForEach-object{$.InputObject}

So what you want to do is use the $_.InputObject as input for Get-Service which can then be piped into Start-Service. Have a look at the following example and let me know if it makes sense:

Compare-Object -ReferenceObject $(Get-Content C:\before.txt) -DifferenceObject $(Get-Content C:\after.txt)|
Where-Object {$_.SideIndicator -eq "=>"}| ForEach-object{Get-Service $_.InputObject | Start-Service}

What you should consider though is that there is no error handling, or logging to the console. If you would like to verify if everything is running you would have to run the command again without the | ForEach-Object portion of the pipeline.

I wouldn’t use TXT files for the comparison. Use Export-CliXML to create your comparison files, and compare those. Limit the comparison to whatever properties you want, but XML will produce a more useful input object, especially when it comes to debugging.

Thanks Jaap for getting it real quick, however I am still unable to get the auto fix done. It looks like the .txt file doesn’t contain the headers (Name and Status) and that’s why it is unable to find the difference object in terms of service. It gives me below error; I also tried for .csv and .xml files neither of them worked though. Can you put something together for this.

PS C:> Compare-Object -ReferenceObject $(Get-Content C:\before.txt) -DifferenceObject $(Get-Content C:\after.txt)|
Where-Object {$.SideIndicator -eq “=>”}| ForEach-object{Get-Service $.inputobject | Start-Service}

[b]Get-Service : Cannot find any service with service name ‘Stopped BITS Background Intelligent Transfer Ser…’.
At line:2 char:58

  • Where-Object {$.SideIndicator -eq “=>”}| ForEach-object{Get-Service $.inputobj …
  •                                                      ~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : ObjectNotFound: [Stopped BITS …Transfer Ser…:String] [Get-Service], ServiceCommandException
    • FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand[/b]

Ohk… I have got the solution.

Get-WmiObject -Class win32_service | where {$.state -ne ‘Running’ } | Export-Clixml -Path “C:\before.xml”
$Bfr_Rbt = Import-Clixml -Path “C:\before.xml”
Get-WmiObject -Class win32_service | where {$
.state -ne ‘Running’ } | Export-Clixml -Path “C:\after.xml”
$Aft_Rbt = Import-Clixml -Path “C:\after.xml”
$Serv = Compare-Object $Bfr_Rbt $Aft_Rbt -Property name,state | Start-Service

But now I want it for multiple computers, listed in a file. How would I do that?

Okay so it really depends on what kind of information you would like to export, indeed the example I listed only works if you source files would either only contain the displayname or the name of the service. I suggest you use what Don Jones suggested and export your results as CLIXml. Something along these lines should help you get started:

Get-Service | Where-Object -FilterScript {$_.Status -eq 'Running'} |
Export-Clixml -Path C:\Before.xml

Then you could update the ForEach-Object portion of your script to this:

| ForEach-object {
    Get-Service -Name $_.InputObject.Name | Start-Service
}

| ForEach-object {
    Get-Service -Name $_.InputObject.DisplayName | Start-Service
}

Let me know how that works out for you.

Ah sorry didn’t see you response there before I typed mine, it depends you can use Start-Service in combination with Invoke-Command if you have PowerShell Remoting enabled in your environment. If you don’t you could start the services using WMI. Do you have PowerShell Remoting enabled for the computers you want to include in this job?

No, I don’t have remoting enabled for my computer objects.

OK, I have got something… and it works… But I noticed that - "WinRM is not set up to allow remote access to this machine for management.
The following changes must be made:
Set the WinRM service type to delayed auto start.
Start the WinRM service.
Create a WinRM listener on HTTP://* to accept WS-Man requests to any IP on this
machine.

Now, I have 3000 client objects where I want to run this script upon and to change the WinRM Config on all of them is not a good idea.

Is there any other way we can do this?

Invoke-Command -ComputerName (get-content C:\computers.txt) {Get-WmiObject -Class win32_service | where {$.state -ne ‘Running’ } }| Export-Clixml -Path “C:\before.xml”
$Bfr_Rbt = Import-Clixml -Path “C:\before.xml”
Invoke-Command -ComputerName (get-content C:\computers.txt) {Get-WmiObject -Class win32_service | where {$
.state -ne ‘Running’ }} | Export-Clixml -Path “C:\after.xml”
$Aft_Rbt = Import-Clixml -Path “C:\after.xml”
$serv = Compare-Object $Bfr_Rbt $Aft_Rbt -Property Name, State, PSComputerName
Get-Service -name($serv.Name) -ComputerName($serv.PSComputerName) | Start-Service