Good day,
I have the following script below which i am using to get a specific value from a remote pc within the company network.
I am stuck on where I would add the export-csv function so that i can export all the data into a csv file.
any help would be appreciated.
$computers = Get-Content "c:\temp\Servers.txt"
$key = 'SOFTWARE\Fortinet\FortiClient\Sslvpn\Tunnels\RCL SSL VPN'
$valuename = 'Server'
$computers = Get-Content Servers.txt
foreach ($computer in $computers) {
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $computer)
$MachineName = $computer
$regkey = $reg.opensubkey($key)
Write-host $MachineName "," $regkey.getvalue($valuename) `r`n
}
You could use PsCustomObject and then add to it with each loop
$computers = Get-Content "c:\temp\Servers.txt"
$objarray = #()
$key = 'SOFTWARE\Fortinet\FortiClient\Sslvpn\Tunnels\RCL SSL VPN'
$valuename = 'Server'
$computers = Get-Content Servers.txt
foreach ($computer in $computers) {
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $computer)
$MachineName = $computer
$regkey = $reg.opensubkey($key)
Write-host $MachineName "," $regkey.getvalue($valuename) `r`n
$objArray += [PSCustomObject]#{
'MachineName' = $computer
'RegKey' = $RegKey
}
}
$objarray | export-csv c:\export.csv
Output objects inside the loop and pipe these through at the very end to the Export-Csv cmdlet like this:
$computers = Get-Content "c:\temp\Servers.txt"
$key = 'SOFTWARE\Fortinet\FortiClient\Sslvpn\Tunnels\RCL SSL VPN'
$valuename = 'Server'
$computers = Get-Content Servers.txt
$result = foreach ($computer in $computers) {
# do this in a Try{..] Catch {..} construct
try {
$regBase = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $computer)
$regkey = $regBase.OpenSubKey($key)
# output an object with the properties you want
[PsCustomObject]#{'MachineName' = $computer; RegistryValue = $regkey.GetValue($valuename) }
}
catch {
Write-Warning "Could not open registry on server '$computer'"
# output an object with the error
[PsCustomObject]#{'MachineName' = $computer; RegistryValue = "Error opening registry.." }
}
# for good measure, Close the opened registry
finally {
if ($regkey) { $regkey.Close() }
if ($regBase) { $regBase.Close() }
}
}
# output on screen
$result | Format-Table -AutoSize
#output to CSV file
$result | Export-Csv -Path 'c:\temp\ServerRegistryValues.csv' -NoTypeInformation
Related
I'm trying (and failing) to:
Connect to the server by iterating through a list.
Confirm location where file exists (1 of 3 locations).
Replace a string in that file.
I've tried to do this multiple ways. There are two that I have which do part of what I want.
Can someone please help me understand if there's something I'm doing inefficiently or how to put all this together?
This one can loop through the servers and find the file
$ErrorActionPreference = 'SilentlyContinue'
$nope=$null
$servers= Get-Content C:\Servers.txt
foreach ($server in $servers)
{
If (Test-Connection -ComputerName $server -Quiet)
{Invoke-Command -ComputerName $server -ScriptBlock {$file=(Get-Childitem -Path C:\DiskSpace.ps1, D:\DiskSpace.ps1, Y:\DiskSpace.ps1); Write-Host "Found $file on $env:computername."}}
Else {
Write-Host ">> Could not connect to $server."; $nope += $server}
}
Write-Host $nope
...and this one can at least find a local file
$valid=#('')
$paths = #("C:\Users\user_name\Desktop\DiskSpace.ps1","C:\DiskSpace.ps1","D:\DiskSpace.ps1","Y:\DiskSpace.ps1")
Foreach ($path in $paths)
{
if (Test-Path $path)
{$valid += $path}
}
write-host $valid
Here's how I intend to to replace the string:
$ErrorActionPreference = 'SilentlyContinue'
$find=(Get-Childitem -Path C:\, D:\, Y:\ -include DiskSpace.ps1 -Recurse)
Write-Host $find
$ErrorActionPreference = 'Stop'
try {
(Get-Content $find).replace('bad_email#domain.com', 'good_email#domain.com') | Set-Content $find
}
catch {
}
Get-Content $find
You had all the pieces already. Simply loop over your Get-Content command for each file in the Invoke-Command.
$ErrorActionPreference = 'SilentlyContinue'
$servers = Get-Content C:\Servers.txt
$files = #('C:\DiskSpace.ps1', 'D:\DiskSpace.ps1', 'Y:\DiskSpace.ps1')
$report = foreach ($server in $servers) {
if (Test-Connection -ComputerName $server -Quiet) {
$response = Invoke-Command -ComputerName $server -ScriptBlock {
Get-Childitem -Path $using:files | ForEach-Object {
(Get-Content $_).replace('bad_email#domain.com', 'good_email#domain.com') | Set-Content $_
[PSCustomObject]#{
Name = $env:COMPUTERNAME
Message = "$($_.fullname) updated."
}
}
}
if ($response -eq $null) {
[PSCustomObject]#{
Name = $env:COMPUTERNAME
Message = "No files found"
}
} else {
$response
}
} else {
[PSCustomObject]#{
Name = $env:COMPUTERNAME
Message = "Unreachable"
}
}
}
$report
Currently have this, but it only reports the machines with chrome and the version. Id like it to also report the machines that are offline, or more importantly missing the file.
Any tips
ta
$Computers = Get-Adcomputer -Filter *
foreach ($Computer in $Computers)
{
$PC = $computer.dnshostname
$hostname = $PC.split('.')[0]
Write-Host "\\$PC\c`$\Program Files\Google\Chrome\Application\chrome.exe"
$exe = "\\$pc\c`$\Program Files\Google\Chrome\Application\chrome.exe"
if ( Test-Path $exe){
$ver = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($exe).FileVersion
Add-Content -path .\results.csv "$exe,$ver"
}
}
Check if the host is accessible first, then check if the file is present only if the host is actually online. Create custom objects for each case and use a pipeline for exporting them to a CSV.
$Computers | ForEach-Object {
$PC = $_.dnshostname
$exe = "\\$PC\C`$\Program Files\Google\Chrome\Application\chrome.exe"
if (Test-Connection $PC -Count 3 -Quiet) {
if (Test-Path -LiteralPath $exe){
[PSCustomObject]#{
Hostname = $PC
HostOnline = $true
FileExists = $true
FileVersion = [Diagnostics.FileVersionInfo]::GetVersionInfo($exe).FileVersion
}
} else {
[PSCustomObject]#{
Hostname = $PC
HostOnline = $true
FileExists = $false
FileVersion = $null
}
}
} else {
[PSCustomObject]#{
Hostname = $PC
HostOnline = $false
FileExists = $null
FileVersion = $null
}
}
} | Export-Csv '.\results.csv' -NoType
Just check whether the machine is reachable first and write a special entry into the file if it isn't. Similarly just write a different entry if the file can't be found:
$Computers = Get-Adcomputer -Filter *
foreach ($Computer in $Computers)
{
$PC = $computer.dnshostname
$hostname = $PC.split('.')[0]
if (Test-Connection $hostname -Count 1) {
Write-Host "\\$PC\c`$\Program Files\Google\Chrome\Application\chrome.exe"
$exe = "\\$pc\c`$\Program Files\Google\Chrome\Application\chrome.exe"
if ( Test-Path $exe){
$ver = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($exe).FileVersion
Add-Content -path .\results.csv "$exe,$ver"
}
else {
Add-Content -path .\results.csv "File not found"
}
}
else {
Add-Content -path .\results.csv "Not reachable"
}
}
Obviously you might want to change the text. Also wouldn't a column for the machinename make sense?
I'm trying to create a script that can get the user profiles that haven't logged on a specific computer within 30 days NOT using active directory but my script didn't work. I am using Powershell version 3. This is my code:
netsh advfirewall firewall set rule group="Windows Management Instrumentation (WMI)" new enable=yes
$ComputerList = Get-Content C:\temp\Computers1.txt
$myDomain = Get-Content C:\temp\Domain.txt
$csvFile = 'C:\temp\Profiles.csv'
# Create new .csv output file
New-Item $csvFile -type file -force
# Output the field header-line to the CSV file
"HOST,PROFILE" | Add-Content $csvFile
# Loop over the list of computers from the input file
foreach ($Computer in $ComputerList) {
# see if ping test succeeds for this computer
if (Test-Connection $Computer -Count 3 -ErrorAction SilentlyContinue) {
$ComputerFQDN = $Computer + $myDomain
$Profiles = Get-WmiObject -Class Win32_UserProfile -Computer $ComputerFQDN | Where{$_.LocalPath -notlike "*$env:SystemRoot*"}
foreach ($profile in $profiles) {
try {
$objSID = New-Object System.Security.Principal.SecurityIdentifier($profile.LocalPath) | Where {((Get-Date)-$_.lastwritetime).days -ge 30}
#| Where-Object {$_.LastLogonDate -le $CurrentDate.AddDays(-60)}
$objuser = $objsid.Translate([System.Security.Principal.NTAccount])
$objusername = $objuser.value
} catch {
$objusername = $profile.LocalPath
}
switch($profile.status){
1 { $profileType="Temporary" }
2 { $profileType="Roaming" }
4 { $profileType="Mandatory" }
8 { $profileType="Corrupted" }
default { $profileType = "LOCAL" }
}
$User = $objUser.Value
#output profile detail for this host
"$($Computer.toUpper()), $($objusername)" | Add-Content $csvFile
}
} else {
#output failure message for this host
"$($Computer.toUpper()), PING TEST FAILED" | Add-Content $csvFile
}
#LOOP
}
I tried to change the -ge to -le in the line $objSID = New-Object System.Security.Principal.SecurityIdentifier($profile.LocalPath) | Where {((Get-Date)-$_.lastwritetime).days -ge 30}, as well as changing the range after it but it still gave me the same list of computers regardless of my changes.
There are a few problems with the script, most notable is that your use of Where-Object is testing an object (SID) that doesn't know anything about dates.
I would break it down a little differently. I would write a function to catch all the stuff I need to do to attempt to figure out the last logon. That's my goes in my stack of utility functions in case I need it again.
Then I have something to use that function which deals with implementing the logic for the immediate requirement.
So you end up with this. It's a bit long, see what you think.
function Get-LastLogon {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $true)]
[String]$ComputerName = $env:COMPUTERNAME
)
process {
Get-WmiObject Win32_UserProfile -ComputerName $ComputerName -Filter "Special='FALSE'" | ForEach-Object {
# Attempt to get the UserAccount using WMI
$userAccount = Get-WmiObject Win32_UserAccount -Filter "SID='$($_.SID)'" -ComputerName $ComputerName
# To satisfy WMI all single \ in a path must be escaped.
# Prefer to use NTUser.dat for last modification
$path = (Join-Path $_.LocalPath 'ntuser.dat') -replace '\\', '\\'
$cimObject = Get-WmiObject CIM_DataFile -Filter "Name='$path'" -ComputerName $ComputerName
if ($null -eq $cimObject) {
# Fall back to the directory
$path = $_.LocalPath -replace '\\', '\\'
$cimObject = Get-WmiObject CIM_Directory -Filter "Name='$path'" -ComputerName $ComputerName
}
$lastModified = $null
if ($null -ne $cimObject) {
$lastModified = [System.Management.ManagementDateTimeConverter]::ToDateTime($cimObject.LastModified)
}
# See if LastUseTime is more useful.
$lastUsed = $null
if ($null -ne $_.LastUseTime) {
$lastUsed = [System.Management.ManagementDateTimeConverter]::ToDateTime($_.LastUseTime)
}
# Profile type
$profileType = switch ($_.Status) {
1 { "Temporary" }
2 { "Roaming" }
4 { "Mandatory" }
8 { "Corrupted" }
0 { "LOCAL" }
}
[PSCustomObject]#{
ComputerName = $ComputerName
Username = $userAccount.Caption
LastChanged = $lastModified
LastUsed = $lastUsed
SID = $_.SID
Path = $_.LocalPath
ProfileType = $profileType
}
}
}
}
$myDomain = Get-Content C:\temp\Domain.txt
Get-Content C:\temp\Computers1.txt | ForEach-Object {
$ComputerName = $_ + $myDomain
if (Test-Connection $ComputerName -Quiet -Count 3) {
Get-LastLogon -ComputerName $ComputerName | Select-Object *, #{Name='Status';Expression={ 'OK' }} |
Where-Object { $_.LastChanged -lt (Get-Date).AddDays(-30) }
} else {
# Normalise the output so we don't lose columns in the export
$ComputerName | Select-Object #{Name='ComputerName';e={ $ComputerName }},
Username, LastChanged, LastUsed, SID, Path, ProfileType, #{Name='Status';Expression={ 'PING FAILED' }}
}
} | Export-Csv 'C:\temp\Profiles.csv' -NoTypeInformation
I am using the following suggestion provided in this link:
Experts-Exchange
I am trying to take a server (host name) list and save the host name and IP address in a .csv file.
Using the following Powershell code, I do see the host name but the same IP address, for every server, in the results pane.
$servers = get-content "C:\TEMP\servers.txt"
$serversAndIps = "C:\TEMP\List_of_servers_with_ips.csv"
$results =#()
foreach ($server in $servers) {
$results =#()
$result = "" | Select ServerName , ipaddress
$result.ipaddress = [System.Net.Dns]::GetHostAddresses($server)
foreach($a in $addresses) {
"{0},{1}" -f $server, $a.IPAddressToString
}
$result.servername = $server
$results += $result
}
$results | export-csv -NoTypeInformation $serversandips
When I open the .csv file, I get this:
"ServerName","ipaddress"
"Server_name_1","System.Net.IPAddress[]"
If I run this PowerShell script, I can get the host name and the correct IP address in the results pane. I just need to know how to transfer the results to a .csv file.
$servers = get-content "C:\TEMP\servers.txt"
foreach ($server in $servers) {
$addresses = [System.Net.Dns]::GetHostAddresses($server)
foreach($a in $addresses) {
"{0},{1}" -f $server, $a.IPAddressToString
}
}
Any suggestions?
Looks like some simple typos at work.
$result was being reset inside the in the loop
$addresses inside the loop wasn't assigned.
$result.ipaddress was not assigned to $a.IPAddressToString for the output object.
Try this:
$servers = get-content "X:\servers.txt"
$serversAndIps ="X:\test.csv"
$results = #()
foreach ($server in $servers)
{
$result = "" | Select ServerName , ipaddress
$result.ipaddress = [System.Net.Dns]::GetHostAddresses($server)
$addresses = [System.Net.Dns]::GetHostAddresses($server)
foreach($a in $addresses)
{
"{0},{1}" -f $server, $a.IPAddressToString
$result.ipaddress = [System.Net.Dns]::GetHostAddresses($server)
}
$result.servername = $server
$result.ipaddress = $a.IPAddressToString
$results += $result
}
$results | export-csv -NoTypeInformation $serversandips
Two issues,
I want a constaint ping to the two servers, and output to a .csv file.
The script below only runs twice and the output doesn't work. I'm a power newbie so please go easy.
$servers = "server1","server2"
$collection = $()
foreach ($server in $servers)
{
$status = #{ "ServerName" = $server; "TimeStamp" = (Get-Date -f s) }
if (Test-Connection $server -Count 1 -ea 0 -Quiet)
{
$status["Results"] = "Up"
}
else
{
$status["Results"] = "Down"
}
New-Object -TypeName PSObject -Property $status -OutVariable serverStatus
$collection += $serverStatus
}
$collection | Export-Csv -LiteralPath .\ServerStatus.csv -NoTypeInformation
The output works fine. Just run the script and then Invoke-Item ServerStatus.csv
If you want it to run forever just wrap the whole thing in a while loop:
$servers = "server1","server2"
$collection = $()
while(1) {
foreach ($server in $servers)
{
...
}
$collection | Export-Csv -LiteralPath .\ServerStatus.csv -NoTypeInformation
}