Powershell recursive remote registry export to csv - powershell

I am trying to export in CSV format an entire registry folder from remote computer but I have no result and I am not able to set the remote computer I am trying to query.
$RegPath=HKLM\Software\Wow6432Node\Google
Get-ChildItem $RegPath -Recurse -ErrorAction SilentlyContinue| Export-CSV -path $ExportFile -notypeinformation

To get a registry item on a remote PC you accomplish this is two ways. First over WSMAN using Invoke-Command
Invoke-Command -ComputerName "ExampleComputer" -ScriptBlock {
Get-ChildItem HKLM:\Software\Wow6432Node\
} | Export-CSV -path $ExportFile -notypeinformation
Or you can use .Net methods over Remote Registry
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', "ExampleComputer")
$RegKey= $Reg.OpenSubKey("Software\\Wow6432Node\\Google")
$Value = $RegKey.GetValue("ExampleValue")
$SubKeys = $RegKey.GetSubKeyNames()

I don't think Get-ChildItem accepts a remote PC name, you would need to use something like Get-WmiObject with registry class.
you're best bet is to use psremoteregistry
Import-Module PSRemoteRegistry in an elevated window then use. You could use the native win32 registry class in .net but it's a bit more advanced.
https://msdn.microsoft.com/en-us/library/8zha3xws(v=vs.110).aspx

$ScriptBlock=#'
$Table=#()
$RegKeys=Get-ChildItem -Path $RegPath -Recurse
$RegKeys=#($RegKeys)
for ($i=0; $i -lt $RegKeys.Count; $i++) {
$RegKeys[$i].Property | ForEach-Object { $TableRow=New-Object -Type PSObject -Property #{Key=$RegKeys[$i].Name;Value=$_;Data=$RegKeys[$i].GetValue($_)}; $Table+=$TableRow }
}
$Table
'#
$ScriptBlock=[System.Management.Automation.ScriptBlock]::Create($ScriptBlock)
$Results=Invoke-Command -ComputerName $ComputerName -ScriptBlock $ScriptBlock
$Results | Select-Object -Property Key,Value,Data | Export-Csv -Path $ExportPath -Encoding ASCII -NoTypeInformation

Related

How to get details of OS name, .net framework details for multiple servers using powershell?

I am trying to get details of OS Name and .net framework details for multiple servers using PowerShell script below.
$servers = Get-Content -Path "C:\Users\vinay\Desktop\servers.txt"
Foreach ($s in $servers)
{
write-host $s
$s.PSDrive
$s.PSChildName
Add-Content C:\Users\vinay\Desktop\specs.txt "Specs:"
$OS = (Get-WmiObject Win32_OperatingSystem).CSName
Add-Content C:\Users\vinay\Desktop\specs.txt "`nOS:$OS"
$Bit = (Get-WMIObject win32_operatingsystem).name
Add-Content C:\Users\vinay\Desktop\specs.txt "`nOS Bit: $Bit"
$name = (Get-WmiObject Win32_OperatingSystem).OSArchitecture
Add-Content C:\Users\vinay\Desktop\specs.txt "`nServer Name: $name"
$dotnet = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse | Get-ItemProperty -Name version -EA 0 | Where { $_.PSChildName -Match '^(?!S)\p{L}'} | Select PSChildName, version
Add-Content C:\Users\vinay\Desktop\specs.txt "`n.NET VERSION $dotnet"
$release = (Get-ItemProperty "HKLM:SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full").Release
Add-Content C:\Users\vinay\Desktop\specs.txt "`nRelease number: $release"
Add-Content C:\Users\vinay\Desktop\specs.txt "`n----------------------------"
}
But i am getting details of the server in which i am running the script but not for other servers in the text file.
however write-host $s reads all the servers in the text file. Please help where i am doing wrong.
Continuing from my comment, you need to perform your code looping over the servers in your list and have that code run on that server instead of your own machine you are running the script from.
Also, I would have the code output objects instead of trying to add lines to a text file, so that you ca save the results in a structured format like CSV.
Try
$servers = Get-Content -Path "C:\Users\vinay\Desktop\servers.txt"
$specs = foreach ($s in $servers) {
if (Test-Connection -ComputerName $s -Count 1 -Quiet) {
Write-Host "Probing server $s"
# you may need to add parameter -Credential and supply the credentials
# of someone with administrative permissions on the server
Invoke-Command -ComputerName $s -ScriptBlock {
$os = (Get-CimInstance -ClassName Win32_OperatingSystem)
Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse |
Get-ItemProperty -Name Version, Release -Erroraction SilentlyContinue |
Where-Object { $_.PSChildName -Match '^(?!S)\p{L}'} |
ForEach-Object {
[PsCustomObject]#{
'ComputerName' = $os.CSName
'Operating System' = $os.Caption
'Architecture' = $os.OSArchitecture
'Net Version' = [version]$_.Version
'Net Framework' = $_.PsChildName
'Net Release' = $_.Release
}
}
}
}
else {
Write-Warning "Computer '$s' cannot be reached.."
}
}
# remove extra properties PowerShell added
$specs = $specs | Select-Object * -ExcludeProperty PS*, RunspaceId
# output on screen
$specs | Format-Table -AutoSize
# output to CSV file you can open in Excel
$specs | Export-Csv -Path 'C:\Users\vinay\Desktop\specs.csv' -UseCulture -NoTypeInformation

Is it possible to speed up scanning a list of computers for specific service names?

I'm kind of a newbie to PowerShell and I am currently making a simple service monitoring script. Right now I have a list of computer names and a list of service names that I scan for.
I save the scan to a log. I am wondering if there is any way I can speed up my PowerShell code? I'm not sure if I am using the quickest methods for the job.
Are there any known alternatives to this code that would scan services quicker?
$myServices = $PSScriptRoot + "\services.txt" # $PSScriptRoot references current directory
$myServers = $PSScriptRoot + "\servers.txt"
$Log = $PSScriptRoot + "\svclog.csv"
$LogLive = $PSScriptRoot + "\svclogLive.csv"
$serviceList = Get-Content $myServices
Remove-Item -Path $Log
$results = Get-Content $myServers | ForEach-Object {
foreach ($service in $serviceList) {
if ($s=get-service -computer $_ -name $service -ErrorAction SilentlyContinue)
{
$s | select MachineName, ServiceName, Status, StartType
} else {
# "$_ - Service '$service' does not exist."
}
}
}
$results | Export-CSV $Log -notypeinformation
# Create a second current log that Python can read while this script runs
Copy-Item -Path $Log -Destination $LogLive
Use Invoke-command
$serviceList = Get-Content $myServices
#some code
$results = Get-Content $myServers
Invoke-command -ComputerName $results -ScriptBlock {
Param($MyServices)
Get-Service -Name $MyServices | Select-Object -Property ServiceName, Status, StartType
} -ArgumentList $MyServices,$Null | Select-Object -Property ServiceName, Status, StartType,PSComputerName |
Export-Csv -NoTypeInformation -Path $Log
#For getting starttype in Version 2.0
Get-wmiObject -class Win32_Service -Filter "Name='BITS'" | Select-Object -Property Name, State, startMode
You can try capturing all of the target server's services in an array and looking through it rather than calling get-service on every service you are searching for:
$myServices = $PSScriptRoot + "\services.txt" # $PSScriptRoot references current directory
$myServers = $PSScriptRoot + "\servers.txt"
$Log = $PSScriptRoot + "\svclog.csv"
$LogLive = $PSScriptRoot + "\svclogLive.csv"
$serviceList = Get-Content $myServices
Remove-Item -Path $Log
$results = Get-Content $myServers | ForEach-Object {
# All of the services in one grab
$serverServices = #(Get-Service -computer $_ -ErrorAction SilentlyContinue)
if ($serverServices) {
foreach ($service in $serviceList) {
#Note: this inner use of another $_ may confuse PowerShell...
if ($s = ($serverServices | Where {$_.Name -eq $service}))
{
$s | select MachineName, ServiceName, Status, StartType
} else {
# "$_ - Service '$service' does not exist."
}
}
}
}
$results | Export-CSV $Log -notypeinformation
# Create a second current log that Python can read while this script runs
Copy-Item -Path $Log -Destination $LogLive

Return running process status for servers in Powershell and export to CSV

I am trying to get my head around Powershell and have the following:
$servers = Get-Content -Path C:\servers.txt
Get-Process -name AVProcess -cn $servers | % where {$_.Status -eq "Running"}
#Export-Csv -path "C:\server-process-sophos.csv"
I get an error, it looks like i cant use the $servers Variable within the parameter computername, also sending to the CSV file is way off. Ideally i'd like to be able to pipe each server name, status of the process into rows in a CSV.
I am trying to return a list of servers which do/dont have that process running or not - so i can see if they have AV installed essentially for an inventory report (this is not good if some dont have AV!!!). How can i best go about this?
Thanks in advance
Get-Process doesn't have a property "Status." It is better/easier to check service status on each machine using Get-Service. You just need to modify service name in this code so it matches your service name. Also output goes to two different files, one is used when service is available for checking, the other is used when there is no service with your needed name. It works with PowerShell V3.
$servers = Get-Content -Path C:\servers.txt
$ErrorActionPreference='stop'
ForEach ($server in $servers) {
try
{
Get-Service -name <enterServiceNameHere> -cn $server | Export-Csv -append -Path "C:\server-process-sophos.csv" -noType -Force
}
catch [System.Management.Automation.ActionPreferenceStopException]
{
$psObject = $null
$psObject = New-Object psobject
$OutputString = "cannot find this service on: " + $server
Add-Member -InputObject $psObject -MemberType noteproperty -Name "List" -Value $OutputString
Export-Csv -InputObject $psObject -Append -path "C:\ServersWithNoService.csv" -NoType -Force
}
}

Get-content Pipe to Select String and retrieve ComputerName

I'm trying to write a script that I can look at a list of remote servers, search for certain file type. Then if the File consists with a certain string i want to know what file that is and on what computer.
I started with the basics but when I do Select-String I can't retrieve the file nor can i find the computer name, it just outputs the same string as i have in my script.
I'm sure i'm missing something basic but any suggestions here will greatly be appreciated.
$servers = ArrayofServers
ForEach ($server in $Servers){
invoke-command -computername $server {Get-ChildItem "D:\Folder\Location\Windows\" -Include *.txt -Recurse |
Get-Content |
Select-String 'String to Select' |
Out-String
} -Credential $credential }
I want to be able to Select FileName,Pscomputername and Select-String.
I find it easier to break the pipeline. I have tested this code successfully:
$Servers = #("ArrayofServers")
foreach ($Server in $Servers)
{
Invoke-Command -ComputerName $Server -ScriptBlock {
$Results = $false
$SearchResults = Get-ChildItem "D:\Folder\Location\Windows\" -Include *.txt -Recurse
foreach ($SearchResult in $SearchResults)
{
If ($SearchResult | Get-Content | Select-String 'String to Select')
{
$SearchResult.FullName
$SearchResult | Get-Content
$Results = $true
}
}
If ($Results)
{
$env:COMPUTERNAME
}
} -Credential $Credential
}

Detecting files on a remote server

Guessing remote registry isn't available (hardened builds so service isn't running) - I can't query the registry for a specific value. However a file is present on the server I am analysing which provides the data I need. Thus far I have written the following - I would appreciate if this can be reviewed as it just hangs - I'm guessing that I would benefit from a if exists statement for the parent directory..
Suggestions and help very much appreciated (only been using PowerShell for a short time so working hard to get to grips with this.
Set-ExecutionPolicy RemoteSigned -ErrorAction SilentlyContinue
$servers = Get-Content -Path C:\Windows\System32\list3.txt
$out = ForEach ($server in $servers)
{
invoke-command -computername $server {Get-ChildItem -Path "C:\ProgramData\Microsoft\Microsoft Antimalware\Definition Updates\" -Exclude Backup -Filter mpavdlta.vdm -Recurse | Select-Object -Last 1 | Select LastWriteTime | ft -AutoSize}
}
$out|Out-File C:\Temp\Versions.log
$servers = Get-Content -Path "X:\ServerList.txt"
$logfile = "X:\Versions.log"
$Include = "Include.file"
$out = ForEach ($server in $servers)
{
Write-Output(Get-ChildItem -Path "\\$Server\X$\Remote Folder\Structure\" -Exclude Backup -Filter $Include -Recurse | Select-Object -Last 1 | Select LastWriteTime | ft -AutoSize) | Out-File $logFile
}
$out
Are you using account that has privileges on remote machine. If so this should provide a path to go down. This will pull server name from list and interrogate via \UNC\admin$ share. Serverlist.txt was just a list of machines in the following format.
machinename.domain.com
I had a look at your original request. Can you not loop through the serverlist and start the remote reg service, do your job and then stop it.
Something like.
$servers = Get-Content -Path "X:\ServerList.txt"
$Service = "Remote Registry"
$out = ForEach ($server in $servers)
{
Get-Service -Name $Service -ComputerName $Server | Set-Service -Status Running
Do remote reg stuff
Get-Service -Name $Service -ComputerName $Server | Set-Service -Status Stopped
}
$out
https://technet.microsoft.com/en-us/library/hh849849.aspx
Your script works, but it might be hanging due to your query (sounds like its capturing too many items). Does the ".vdm" file reside on that exact directory? You can remove the -Recurse if it does. Here's a modified version of yours. I just added the connection and destination checks.
Set-ExecutionPolicy RemoteSigned -ErrorAction SilentlyContinue
$servers = Get-Content -Path C:\Windows\System32\list3.txt
$out = ForEach ($server in $servers)
{
If(Test-Connection $server -Quiet){
Invoke-Command -Computername $server {
param([string]$parentPath)
If(Test-Path $parentPath)
{
#Write-Host "$parentPath Exists on $env:COMPUTERNAME."
Get-ChildItem -Path $parentPath -Exclude Backup -Filter mpavdlta.vdm -Recurse | Select-Object -Last 1 | Select LastWriteTime | ft -AutoSize
}
Else{
#Write-Host "$parentPath does not exist on $env:COMPUTERNAME"
}
} -ArgumentList $parentPath
}
Else { Write-host "Unable to connect to $server." }
}
$out | Out-File C:\Temp\Versions.log