Get-hotfix on multiple computers and exporting to CSV - powershell

How do I properly use $_ in out-file? Here's my code:
get-content computers.txt |
Where {$_ -AND (Test-Connection $_ -Quiet)} |
foreach { Get-Hotfix -computername $_ } |
Select CSName,Description,HotFixID,InstalledBy,InstalledOn |
convertto-csv | out-file "C:\$_.csv"
I'm trying to execute a get-hotfix for all the computers listed in the text file then I want them to be exported to CSV with the computer name as the filename.

You need one pipeline to process the computers.txt files, and a nested one inside the foreach to process the list of hotfixes for each computer:
get-content .\computers.txt |
Where {$_ -AND (Test-Connection $_ -Quiet)} |
foreach {
Get-Hotfix -computername $_ |
Select CSName,Description,HotFixID,InstalledBy,InstalledOn |
convertto-csv | out-file "C:\$_.csv"
}
Edit: Changed computers.txt to .\computers.txt, as this is required for local paths in powershell

i can see with this:
get-content .\computers.txt | Where {$_ -AND (Test-Connection $_ -Quiet)} | foreach{ Get-Hotfix -id KB4012212 -computername $_ | Select CSName,Description,HotFixID,InstalledBy,InstalledOn | convertto-csv | out-file "C:\$_.csv" }
i can see only in which PC is the fix (KB4012212) installed.
it's possible to see the following
CSNAME Fix(Inst/NotInst)
PC1 FIxInstalled
PC2 FixNotinstalled
PC3 FixnotInstalled
..
..
etc

I monkeyed with this for a while and nothing I found on-line worked until I used this combo. 
I used the method is this thread but it was SO slow and I wanted to learn more about using jobs so this is what ended up working for me on Windows 7 PS Ver 4.
All other options were either too slow or did not return data from the remote system.
$VMs = get-content C:\WinVms.txt #Generate your hostnames list however you deem best.
foreach ($vm in $vms)
{
Write-Host "Attempting to get hotfixes on:" $vm
invoke-command -computername $vm -ScriptBlock {start-job -scriptblock {(get-hotfix | sort installedon)[-1]} | wait-job | receive-job} -AsJob
}
start-sleep 60 # give it a minute to complete
get-job | ? { $_.state -eq "Completed"} | receive-job -keep | export-csv c:\temp\win-patch.csv
you can check your failures too like this: 
get-job | ? { $_.state -eq "Failed"}

Related

Output running services to csv with computer name

I need to generate a csv containing running services to csv with the corresponding computer name
I know there is a simple way to do this and I have been tinkering with creating a new psobject, but I am not sure how to pipe the results to the new-object...
Here is what I am using:
$Input = "SomePath"
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "$Input"
ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Export-csv -Path "$Output"
}
What I need in the CSV is:
ComputerName, ServiceName, DisplayName
basically, I need to add the computer name to the array.
If you want to be able to pipe the results, use a foreach-object.
$Output = "SomeOtherPath"
Get-Content -Path "SomePath" | ForEach-Object {
Get-Service -ComputerName $_ | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName
} | Export-csv -Path "$Output"
If you want to stick to a foreach statement, collect it all first then export it.
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "SomePath"
$results = ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName
}
$results | Export-csv -Path "$Output"
Try like this (Don't use $Input as variable name)
$InputX = "SomePath"
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "$Input"
ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName | Export-csv -Path "$Output"
}

How to check if hotfix KBxxxxxx (example: KB4012212) is installed in the PC or not?

I will create (with PowerShell script) a table and add the result(Positive/negative) to it.
I have a text file computers.txt, in which all PCs are listed.
Like this
CSNAME Hotfixinfo
PC1 is installed
PC2 is not installed
PC3 is installed
etc.
With my actual script I can only see the positive result.
Get-Content .\computers.txt | Where {
$_ -and (Test-Connection $_ -Quiet)
} | foreach {
Get-Hotfix -Id KB4012212 -ComputerName $_ |
Select CSName,HotFixID |
ConvertTo-Csv |
Out-File "C:\$_.csv"
}
I'd suggest parsing through and handling the positive and negative results (also faster than the pipeline ForEach-Object):
:parse ForEach ($Computer in (Get-Content C:\Path\computers.txt))
{
If (Test-Connection $Computer -Quiet)
{
$Result = Get-Hotfix -Id KB4012212 -ComputerName $Computer -ErrorAction 'SilentlyContinue'
If ($Result)
{
$Result |
Select-Object -Property CSName,HotFixID |
ConvertTo-Csv -NoTypeInformation |
Out-File "C:\$Computer.csv"
Continue :parse
}
"`"CSName`",`"HotFixID`"`r`n`"$Computer`",`"NUL`"" |
Out-File "C:\$Computer.csv"
} Else { Write-Host 'Unable to connect to $Computer' }
}

Adding new lines to Existing CSV using powershell?

I wrote a script that would fetch all the services running under an account name.
This part works fine except I want to add results to an existing csv. Add-content is messing up with my format. Please help as i am new here.
script:
$servers = #("a", "b")
$domain = "abc.com"
foreach($server in $servers){
$serverFQDN = $server+"."+"$domain"
Invoke-Command -computername $serverFQDN{
param($server)
Write-host "On" + $server -ForegroundColor Yellow
Get-WMIObject Win32_Service | Where-Object {$_.startname -match "ciqdev*" }
# | where-object {$_.state -eq "running"}
}-argumentlist $server | select pscomputername,caption | export-Csv Z:\RT\myCSV.csv
}
Use -Append :
export-Csv Z:\RT\myCSV.csv -Append

Powershell - Improving Script Execution Time

I've got a script which goes out to computer names from a text file and then polls the services on those machines and writes the results back to a text file.
Here's what I currently have set up:
$Computers = Get-Content computername.txt
$Output = Foreach ($Computer in $Computers) {
Write-Output "`n" "Status of $Computer".ToUpper()
Get-WMIobject -Computername $Computer win32_service | Where-Object {$_.startname -ne "LocalSystem" -and $_.startname -ne "localservice" -and $_.startname -notlike "*AUTHORITY*"} | ft name, startname, startmode, state
}
$Output | Out-File ServiceReport.txt
Is there a way to run multiple sessions at once instead of processing this incrementally? IE - send the command to all the systems at once and then receive the response and record appropriately? I've looked in to Invoke-Command and a few other things but have yet to improve time, get results to write back to the file, or get those options working generally.
Get-WMIObject will multi-thread. You just need to give it more than one computer at a time to work with:
$Computers = Get-Content computername.txt
Get-WMIobject -Computername $Computers win32_service |
Where-Object {$_.startname -ne "LocalSystem" -and $_.startname -ne "localservice" -and $_.startname -notlike "*AUTHORITY*"} |
ft PSComputerName, name, startname, startmode, state |
Out-string |
Out-File ServiceReport.txt
You'll lost the ability to have that "Status of $Computer" line before each one but you can make up for it by including the computer name in the selected objects.

Get-Service on multiple remote machines

I can only get the command to return the services on the first computer in the text file.
Is there a better way than for-each for this task?
Get-Service *vault* -ComputerName (Get-Content c:\users\sean\desktop\js.txt) | select name,status,machinename | sort machinename | format-table -autosize
Try it without the get-content. Try this:
Get-Service *vault* -ComputerName c:\users\sean\desktop\js.txt | select name,status,machinename | sort machinename | format-table -autosize
If that doesn't work, then try:
$Computers = Get-Content c:\users\sean\desktop\js.txt
Get-Service *vault* -computername $Computers | Select name,status,machinename |sort machinename |format-table -autosize
If you are eager for a one-liner then try this:
Get-Content c:\users\sean\desktop\js.txt | Get-Service *vault* | Select name,status,machinename |sort machinename |format-table -autosize
I would try the top one first. I would test, but I don't have access to anything I can do a proper test right now.
$Computers = get-content .\desktop\test.txt
$Service = "Vault"
foreach ($computer in $computers) {
$computer
$Servicestatus = get-service -name $Service -ComputerName $computer
}
$Servicestatus | select-object Name,Status,MachineName | format-table -Autosize
This works for me, it gives me each of the computers in the text file, and it looks for the service.
This is what I use. I get the list of computers from an OU in AD.
Import-Module ActiveDirectory
$ou = "OU=Servers,DC=Domain,DC=com"
$servers = Get-ADComputer -Filter * -SearchBase $ou | select-object -expandproperty name
Foreach ($server in $servers){
$Data = Get-Service -ServiceName *IIS*,*TomCat*,*httpd* -ComputerName $server | select machinename,name | sort machinename | format-table -AutoSize
Write($Data) | Out-File .\WebServices.txt -Append
}
$servers = Get-Content .\servers.txt
Foreach ($server in $servers) {
"$server"
Get-Service -ComputerName $Server -name -like "*vault*"
"-------------------"
}
Following a memory limitation limit with older versions of PowerShell, I was required to refresh my code:
Old code:
gwmi win32_service -computer $allcomputers | Select-Object __SERVER,Name,state,startmode,StartName
New code:
`$servers = Get-Content "computers.txt"
Foreach ($server in $servers) {
Get-WmiObject -Class WIN32_service -ComputerName $server |
Select-Object __SERVER,Name,state,startmode,StartName |
Export-Csv -path "Report.CSV" -NoTypeInformation -Append
}`
This is how you can get list of all services in your AD domain:
Get-ADComputer -Filter {OperatingSystem -Like “Windows 10*”} | ForEach-Object {Get-WmiObject -Class Win32_Service -Computer $_.Name}
More useful examples on this (get list of services for all computer listed in a text file, etc.):
https://www.action1.com/kb/list_of_services_on_remote_computer.html
Get-Service -ComputerName ... has a bug in PowerShell 2.0 that only returns the first computer. This is fixed in newer versions so if you upgrade to PowerShell 3.0 or newer, your original code will work fine.
As a workaround, use a foreach-loop to run Get-Service once for each computer:
Get-Content c:\users\sean\desktop\js.txt |
ForEach-Object { Get-Service -Name *vault* -ComputerName $_ } |
Select-Object -Property Name, Status, MachineName |
Sort-Object -Property MachineName |
Format-Table -AutoSize
Nick's solution totally doesn't work for me. I ended up writing a quick and dirty one that works:
$servers = Get-Content .\servers.txt
Foreach ($server in $servers) {
"$server"
Get-Service *vault*
"-------------------"
}