Powershell Export to CSV with three coumns - csv

function getServerInfo
{
$serverList = Get-Content -Path "C:\Users\username\Desktop\list.txt"
$cred = Get-Credential -Credential "username"
foreach($server in $serverList)
{
$osVersion = gwmi win32_operatingSystem -ComputerName $server -ErrorAction SilentlyContinue
if($osVersion -eq $null)
{
$osVersion = "cannot find osversion"
}
$psv = Invoke-Command -ComputerName $server -ScriptBlock {$PSVersionTable.PSVersion.Major} -ErrorAction Ignore
if($psv -eq $null)
{
$psv2 = Invoke-Command -ComputerName $server -Credential $cred -ScriptBlock {$PSVersionTable.PSVersion.Major} -ErrorAction Ignore
Write "$server has $($osVersion.Caption)and PSVersion is $psv2"
}
else{
Write "$server has $($osVersion.Caption)and PSVersion is $psv"
}
}
}
I am trying to create a csv file with 3 columns.
First column will have $server, second column will have $osVersion and third will have $psv. Please help. thank you!

Rather than using the foreach loop, consider using the ForEach-Object cmdlet so that the results can be piped to other commands. Inside of the ForEach-Object script block, you can calculate the 3 values you need, and then its easy to create CSV string using string interpolation. The results can then be piped to the appropriate output file.
Get-Content -Path C:\Users\username\Desktop\list.txt | ForEach-Object {
$Server = $_
$OSVersion = gwmi Win32_OperatingSystem -ComputerName $Server -ErrorAction SilentlyContinue
$PSVersion = Invoke-Command -ComputerName $Server -ScriptBlock { $PSVersionTable.PSVersion.Major }
"$Server,$OSVersion,$PSVersion"
} | Out-File outputFilename.csv

To export to a CSV using the Export-CSV cmdlet, PowerShell expects an array of objects with the same set of properties to output. For your case you can do that fairly simply as such:
$cred = Get-Credential -Credential "username"
$AllServers=foreach($server in $serverList)
{
[PSCustomObject]#{
'Server' = $Server
'osVersion' = gwmi win32_operatingSystem -ComputerName $server -ErrorAction SilentlyContinue | Select -Expand Caption
'psv' = Invoke-Command -ComputerName $server -ScriptBlock {$PSVersionTable.PSVersion.Major} -ErrorAction Ignore -Credential $cred
}
}
$AllServers | Export-Csv c:\path\to\output.csv -notype

Related

Using PowerShell to verify that a specific service exists from a .txt list of server names

I am trying to verify that a specific service exists from a .txt list of server names and then output to a file. In this case I need to also add credentials so I need to use the Invoke-Command. What am I doing wrong here?
clear
start-transcript -path .\Log.txt
$servers = Get-Content .\Resources\Lab.txt
$cred = get-credential domain\Username
$name = Read-Host -Prompt 'Input your service name'
function Getinfo() {foreach($server in $servers)
{
Get-Service | Where-Object { $_.Name -eq $name}-and {$_.Status -eq "Running"}| Format-Table -AutoSize
}
}
Invoke-Command -credential $cred -ComputerName $servers -ScriptBlock ${function:Getinfo}
Stop-Transcript
I think you mean this?
$servers = Get-Content .\Resources\Lab.txt
$cred = Get-Credential domain\Username
$name = Read-Host -Prompt 'Input your service name'
Invoke-Command -Credential $cred -ComputerName $servers -ScriptBlock {
param($name)
Get-Service | Where-Object { $_.Name -eq $name -and $_.Status -eq "Running"}
} -ArgumentList $name | Format-Table -AutoSize

Need to add If (Test-Connection) cmdlet

Is it possible to add the If (Test-Connection) cmdlet to this script? I want to ping the host first
the run the script if the host its on.
`enter code here`
$sb = { write-host "$env:computername"
Get-ChildItem HKLM:\SOFTWARE\McAfee\AVSolution\DS\ -Recurse | ForEach-Object {
Get-ItemProperty $_.pspath
}
}
$Results = Invoke-Command -ScriptBlock $sb -ComputerName (Get-Content -Path 'C:\computers.txt')
#Show output to screen
Write-Output $Results
$Results | Export-Csv -Path 'C:\computers.CSV' -NoTypeInformation -Append

try-catch bypassing a step

I have a script that tests connection to a list of servers, and if contactable, gets the status of a service, and puts the results into three variables, $Computer, $Ping (True/False), and $Service (Running or Stopped).
The output is in a hashtable but I can only get to show the servers that ARE contactable, and not the ones that cannot be contactable.
I have placed a try/catch in the $Ping block, as well as -ErrorAction Stop, so that it doesn't attempt to run the $Service script, and instead go to the next $Computer in the array. I think I am trying to do two things at once that are conflicting each other:
add the variables to the #Splat and
don't process any further.
There are actually many more remote registry queries in my script, which will be irrelevant if the $Computer cannot be contactable, but I have shortened it for this post.
Function Get-Ping {
$Servers = (gc "c:\temp\test.txt")
foreach ($Computer in $Servers) {
Write-Host
Write-Host "---------------------------------"
Write-Host "QUERYING $Computer"
Write-Host
Write-Host "Performing ping test..."
try {
$Ping = Test-Connection $Computer -Count 1 -ErrorAction Stop
} catch {
Write-Warning "Cannot Ping $Computer"
Write-Host "Trying next computer..."
Write-Host
continue
}
if ($Ping) {$Ping="$True"}
Write-Host $Computer "can be pinged"
$svcRRStopped = $false
if ($Computer -ne $env:COMPUTERNAME) {
Write-Host "Check RemoteRegistry status..."
}
$svcRR = Get-Service -ComputerName $Computer -Include RemoteRegistry
$SelectSplat = #{
Property = (
'Computer',
'Ping',
'Service'
)}
New-Object -TypeName PSObject -Property #{
Computer=$Computer
Ping=$Ping
Service=$svcRR.status
} | Select-Object #SelectSplat
}
}
$results = Get-Ping
$tableFragment = $results | Select 'Computer','Ping','Service'
$tableFragment
Don't make things more complicated than they need to be.
function Get-Ping {
Get-Content 'C:\temp\test.txt' | ForEach-Object {
$isAvailable = [bool](Test-Connection $_ -Count 1 -EA SilentlyContinue)
if ($isAvailable) {
$rreg = Get-Service -Computer $_ -Name RemoteRegistry |
Select-Object -Expand Status
} else {
$rreg = 'n/a'
}
New-Object -Type PSObject -Property #{
Computer = $_
Ping = $isAvailable
Service = $rreg
}
}
}
Get-Ping
You can simply use the -Quiet Parameter:
Test-Connection $_ -Count 1 -Quiet

Calling a function within a function with invoke-command Powershell

I am hoping to call a function within a function in invoke-command. It looks like I am not doing this properly. I get "get-group_users" is not recognized error. Everything is in one ps1 script.
Truncated Script:
function get-session {
$session = New-PSSession -ComputerName $ip -Credential $cred -Auth CredSSP
$ComputerName = $cred.Replace('\Admin',"")
$csv = "C:\Scripts\Serverlists\" + $ComputerName + ".txt"
$subcomps = import-csv $csv | foreach-object {$_.Name}
foreach ($ComputerName in $subcomps)
{
$ComputerName
$xmlWriter.WriteStartElement("Computer",$ComputerName)
Invoke-Command -Session $session -ScriptBlock { (get-groups_users -ComputerName $ComputerName) } -ArgumentList $ComputerName
$xmlWriter.WriteEndElement()
}
Remove-PSSession -ComputerName $ip
}
$ip = '172.16.24.11'
$ComputerName = "COMP1"
$user = '\Admin'
$cred = $ComputerName + $user
(get-groups_users -ComputerName $ComputerName)
(get-session -Credential $cred -ComputerName $ip)
So, I'm leaving out the get-groups_users function. I can post it if someone thinks it will help explain everything. It is a long one. Also i am leaving out the $xmlwriter definitions.
get-groups_users works when it runs on COMP1, but once I enter PSSession and try and use it in invoke-command for the sub comps it doesn't recognize it.
What am I forgetting?
You have to include the get-groups_users function definition inside the -ScriptBlock parameter when you call Invoke-Command. If you don't, the remote session has no knowledge of the get-groups_users function.
Here's how to fix that:
$ScriptBlock = {
function get-groups_users {
############ Put your function's code here ############
}
(get-groups_users -ComputerName $ComputerName)
};
Invoke-Command -Session $session -ScriptBlock $ScriptBlock -ArgumentList $ComputerName

Powershell function throwing null exception

Okay, so I've read up on calling functions and passing parameters in powershell but maybe I'm not understanding something. I am calling a function and passing a couple parameters and everything works fine. It is variable defined within the function that seems to be null when it isn't.
Function:
function get-session {
$session = New-PSSession -ComputerName $ip -Credential $cred -Auth CredSSP
$subcomps = 'COMP1'
foreach ($Computer in $subcomps)
{
$Computer
Invoke-Command -Session $session -ScriptBlock { Get-WmiObject -ComputerName $Computer -Query "SELECT * FROM Win32_Group" }
}
Remove-PSSession -ComputerName $ip
}
Script:
$ip = '123.45.67.89'
$ComputerName = "HOPCOMP"
$user = '\Admin'
$cred = $ComputerName + $user
$ip
$cred
(get-session -ComputerName $ip -Credential $cred)
When I run this:
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty.
Supply an argument that is not null or empty and then try the command again.
+ CategoryInfo : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Of course, if I change $Computer in in the function Get-WMIObject line to COMP1 everything works great. But, the $Computer write out in the foreach loop writes COMP1 successfully.
What am I missing here?
You need to specify the -ArgumentList parameter with your Invoke-Command. For example:
Invoke-Command -Session $session -ScriptBlock {
param($Computer)
Get-WmiObject -ComputerName $Computer -Query "SELECT * FROM Win32_Group"
} -ArgumentList $Computer
The $IP is global and therefore known with the function. The -ArgumentList is needed or populate your $MyScriptBlock a line before acting on it with Invoke-Command.
The function does not know what $ip is.
You need to change the function to accept a parameter of $ip