I am trying to write script that will check servers hostnames.
Now I have:
Computers.txt
192.168.10.10
192.168.10.11
192.168.10.12
and script:
$servers = get-content "C:\Script\computers.txt"
Invoke-Command -Credential company\admin1 -ComputerName $computers -scriptblock {[Environment]::GetEnvironmentVariable("ComputerName")} | out-file C:\Script\report_hostnames.txt
And I have report:
Computer1
Computer2
Computer3
Could you help me add IP adress to report, and error status, like this:
192.168.10.10 Computer1
192.168.10.11 Computer1
192.168.10.12 Computer Unavailable
I tried: foreach; try, catch and if, else but cannot understand how to use it in right way.
Try this:
get-content "C:\Script\computers.txt" | foreach {
$Response = Invoke-Command -Credential company\admin1 -ComputerName $_ -scriptblock {[Environment]::GetEnvironmentVariable("ComputerName")}
write-output "$_ $Response" | out-file C:\Script\report_hostnames.txt
}
Using an array inside the -ComputerName attribute and then piping the output forward to out-file doesn't give you a way to access the contents of -ComputerName attribute (at least that I know of). Breaking it up into a basic foreach does.
You should be able to use DNS to look up the host names. Example:
Get-Content "IPAddresses.txt" | ForEach-Object {
$outputObject = [PSCustomObject] #{
"IPAddress" = $_
"HostName" = $null
}
try {
$outputObject.HostName = [Net.Dns]::GetHostEntry($_).HostName
}
catch [Management.Automation.MethodInvocationException] {
$outputObject.HostName = $_.Exception.InnerException.Message
}
$outputObject
}
Related
I am using powershell to pull basic computer information from all computers on a LAN. These computers are not, and will never be on, a domain. I have had some success in my test runs getting the output for all of the machines to save into the c:\scripts folder on the host machine. I am, however, having to use the Invoke-command for every cmdlet so that I can put the Output destination outside of the {}.
$computers = Get-Content -Path 'c:\scripts\livePCs.txt'
foreach ($computer in $computers) {
$username = '$computer\Administrator'
$password = Get-Content 'C:\scripts\encrypted_password.txt' | ConvertTo-SecureString
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
# Local Mounted Shares Enumeration
Invoke-Command -Computername $computer -Credential $credential {Get-SmbMapping | Format-Table -AutoSize} | Out-File "c:\scripts\ComputerInformation\$computer.mountedshares.ps.txt"
# Local Shares Enumeration
Invoke-Command -Computername $computer -Credential $credential {Get-SmbShare | Format-Table -AutoSize} | Out-File "c:\scripts\ComputerInformation\$computer.localshares.ps.txt"
I would prefer not to have to do this and it becomes problematic when I have to use If/Else statements, where, because I cannot put the destination outside of braces, I get a file cannot be found error (since it is trying to save on the remote host). I tried using a share instead, in the below but now am getting an access to the file path is denied error.
Invoke-Command -Computername $computer -Credential $credential {
$computername = hostname.exe
If ($PSVersionTable.PSVersion -ge '4.0') {
If (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Get-WindowsOptionalFeature -Online -FeatureName *Hyper-V* | Format-Table -AutoSize | Out-File -Width 1024 "\\$env:computername\scripts\ComputerInformation\$computername.hyperv.admin.ps.txt"
if (Get-Command Get-VM -ErrorAction SilentlyContinue) {
Get-VM | Format-Table -AutoSize | Out-File -Width 1024 -Append "c:\scripts\ComputerInformation\$computername.hyperv.admin.ps.txt"
Get-VM | Get-VMNetworkAdapter | Format-Table -AutoSize | Out-File -Width 1024 -Append "c:\scripts\ComputerInformation\$computername.hyperv.admin.ps.txt"
} else {
Write-Host -ForegroundColor Yellow " Hyper-V feature not installed on this host"
}
} else {
Write-Host -ForegroundColor Red " You do not have required permissions to complete this task ..."
}
} else {
Write-Host -ForegroundColor Red " This commands requires at least PowerShell 4.0 ... manual inspection is required"
}
How do I run this one a remote machine using Invoke-Command but save the output to the local c:\scripts folder?
If the goal is to give yourself the option to output to multiple files on the calling system, you could use a hash table ($results) inside of your script block to store your results. Then output that table at the end of your script block. Based on those keys/values, you could output to file.
foreach ($computer in $computers) {
$Output = Invoke-Command -Computername $computer -Credential $credential {
$results = #{}
$computername = hostname.exe
If ($PSVersionTable.PSVersion -ge '4.0') {
If (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
$HyperV = Get-WindowsOptionalFeature -Online -FeatureName *Hyper-V* | Format-Table -AutoSize
if (Get-Command Get-VM -ErrorAction SilentlyContinue) {
$VMInfo = Get-VM | Format-Table -AutoSize
$VMNic = Get-VM | Get-VMNetworkAdapter | Format-Table -AutoSize
} else {
Write-Host -ForegroundColor Yellow " Hyper-V feature not installed on this host"
}
} else {
Write-Host -ForegroundColor Red " You do not have required permissions to complete this task ..."
}
} else {
Write-Host -ForegroundColor Red " This commands requires at least PowerShell 4.0 ... manual inspection is required"
}
$results.Add('HyperV',$HyperV)
$results.Add('VMInfo',$VMInfo)
$results.Add('VMNic',$VMNic)
$results
}
$Output.HyperV | Out-File -Width 1024 "c:\scripts\ComputerInformation\$computer.hyperv.txt"
$Output.VMInfo | Out-File -Width 1024 "c:\scripts\ComputerInformation\$computer.VMInfo.txt"
$Output.VMNic | Out-File -Width 1024 "c:\scripts\ComputerInformation\$computer.VMNic.txt"
}
If the goal is to simply output all data to one location, you can simply store your Invoke-Command result into a variable. Then write the variable contents to file:
$Output = Invoke-Command -Computername $computer -Scriptblock { # my code runs here }
$Output | Out-File "C:\Folder\$computer.txt"
If you are looking to capture Write-Host output in a variable, you will need to send the information stream to the success stream ( { script block } 6>&1 }
You can redirect the output
$YourScriptBlock = { your script }
$result = Invoke-Command -ScriptBlock $YourScriptBlock 4>&1 -Computer $c -Credential $c
Afterwards the contents are in $result
write-output $result
Have a bit of an issue whereby would like to figure out the best way to handle success or failures. Have a powershell query which checks the dcom port range, if it is within the specified value output to a success file, if not a failure file. The issue is, it seems to be outputting the entire serverlist.txt for a success and need to know a way to break this down so it only appends a server (either success/failure) to it, not all at once.
Here is the powershell script contents:
powershell -executionpolicy bypass .\DCOMPortRange.ps1
Where DCOMPortRange.ps1 contains
$computername = Get-Content -Path "C:\Folderpath\serverlist.txt"
$val = (Get-ItemProperty "hklm:SOFTWARE\Microsoft\Rpc\Internet") | Select-Object -ExpandProperty Ports
if($val -eq "50000-50500")
{
Write-Output "$computername" | out-file C:\folderpath\Success.log -append
} Else {
Write-Output "$computername" | out-file C:\folderpath\Failure.log -append
}
The issue is the error path lets say is a success it appends the entire server list.
Please advise?
This is how I would do it. This does require that you do have PSremoting enabled on the servers
$computername = Get-Content -Path "C:\Folderpath\serverlist.txt"
ForEach ($server in $computername) {
$val = Invoke-Command -Computername $server -ScriptBlock {(Get-ItemProperty "hklm:SOFTWARE\Microsoft\Rpc\Internet") | Select-Object -ExpandProperty Ports}
if ($val -ge 50000 -and $val -le 50500) {
Write-Output "$server" | out-file C:\folderpath\Success.log -append
}
Else {
Write-Output "$server" | out-file C:\folderpath\Failure.log -append
}
}
Edit: A change to the if statement
/Anders
$remotecomputername = #("PC1","PC2","RealServerName")
ForEach ($computer in $remotecomputername) {
Invoke-Command -Computername $computer -ScriptBlock { $val = (Get-
ItemProperty "hklm:SOFTWARE\Microsoft\Rpc\Internet") | Select-Object -
ExpandProperty Ports} }
if($val -eq "50000-50500") {
write-host $computer DCOM Port in Range
} else {
write-host $computer DCOM Port not in range
}
Hi I am running this script again multiple servers (initially posted here) & I would like to get each specific servers names to be appeared in the result. But right now, I am able to get with the heading CPU & Memory Usage & then the usage for each server one after the other. Pls let me know how to get each server name & the result.
$Output = 'C:\temp\Result.txt'
$ServerList = Get-Content 'C:\temp\ServerNames.txt'
$ScriptBLock = {
$CPUPercent = #{
Label = 'CPUUsed'
Expression = {
$SecsUsed = (New-Timespan -Start $_.StartTime).TotalSeconds
[Math]::Round($_.CPU * 10 / $SecsUsed)
}
}
$MemUsage = #{
Label ='RAM(MB)'
Expression = {
[Math]::Round(($_.WS / 1MB),2)
}
}
Get-Process | Select-Object -Property Name, CPU, $CPUPercent, $MemUsage,
Description |
Sort-Object -Property CPUUsed -Descending |
Select-Object -First 15 | Format-Table -AutoSize
}
foreach ($ServerNames in $ServerList) {
Invoke-Command -ComputerName $ServerNames {Write-Output "CPU & Memory Usage"}
| Out-File $Output -Append
Invoke-Command -ScriptBlock $ScriptBLock -ComputerName $ServerNames |
Out-File $Output -Append
I see you're running with a loop on the servers names ($ServerNames is each server for each iteration), so why don't you use:
"Working on $ServerNames.." | Out-File $Output -Append
on the first line after the "foreach" statement?
Anyway, I think you can change your script like this:
On the script block add:
Write-Output "CPU & Memory Usage"
hostname | out-file $output -Append # this will throw the server name
Once you have this on the Scriptblock, you can run it like this:
Invoke-Command -ScriptBlock $ScriptBLock -ComputerName $ServerList
($ServerList is the original servers' array, which "Invoke-Command" knows how to handle).
The code below turns off firewall on each remote computers and return any computers that was turned off. I am also trying to retrieve software that has been authorized to pass through firewall for each computer.
I understand that I am using try, catch so is there any way to print the output of $Appfilter to offComp&programsALLO.txt ? The text file just prints the value of $Appfilter.
The output should ideally look like:
Computers:
"name of computer" followed by "programs allowed"
Here is the code:
Get-ADComputer -Filter * | Select-Object -ExpandProperty Name | Out-File .\ADcomputers.txt
$LaunchLine = 'powershell.exe -Version 4.0 -Command "& {netsh advfirewall set allprofiles state off}"'
$Appfilter = 'powershell.exe -Version 4.0 -Command "& {Get-NetFirewallApplicationFilter -program * | fl program}"'
$ComputerList = Get-Content .\adcomputers.txt
foreach($Computer in $ComputerList) {
[String]$wmiPath = "\\{0}\root\cimv2:win32_process" -f $computer
try {
[wmiclass]$Executor = $wmiPath
$executor.Create($LaunchLine, $Appfilter)
} catch {
Add-Content offComp&programsALLO.txt "computers:$Computer, $Appfilter "
}
}
I would use Invoke-Command with the -ComputerName parameter if possible:
#store AD Computer names in an array
$computerList = (Get-ADComputer -Filter *).Name
#declare results arrays
$results = #()
$offline = #()
#for each computer
foreach($computer in $computerList) {
#if computer responds to ping
if(Test-Connection $computer -Count 2 -Quiet -ErrorAction SilentlyContinue) {
#disable firewall
Invoke-Command -ComputerName $computer -ScriptBlock {
netsh advfirewall set allprofiles state off
} | Out-Null
#store retrieved authorized programs list in an array
$programs = Invoke-Command -ComputerName $computer -ScriptBlock {
(Get-NetFirewallApplicationFilter).Program
}
#build results object and add it to results array
$results += [PSCustomObject]#{
ComputerName = $computer
Programs = $programs -join ";"
}
} else {
#build results object and add it to offline array
$offline += [PSCustomObject]#{
ComputerName = $computer
Status = "OFFLINE"
}
}
}
#export results to files
$results | Out-File "report.txt"
$offline | Out-File "offline.txt"
I'm looking for help with my script again :)
I have a script that will query list of servers to find if specific service is installed. This works fine. However, I know that there are some servers in my list that I don't have access to, or there are different credentials. How do I make this visible in output? Because I only get output that service is not installed, which is not true, I just don't have correct credentials.
$name = "BESClient"
$servers = Get-content C:\list.txt
function Confirm-WindowsServiceExists($name)
{
if (Get-Service -Name $name -Computername $server -ErrorAction Continue)
{
Write-Host "$name Exists on $server"
return $true
}
Write-Host "$name does not exist on $server"
return $false
}
ForEach ($server in $servers) {Confirm-WindowsServiceExists($name)}
Also, I'd like to have output formatted into the one line, e.g.:
Server1 Service running
Server2 Service not installed
Server3 no access
etc...
Thanks a lot for any help.
Here's an option which just displays the content of the error on failure:
function Confirm-WindowsServiceExists($name)
{
if (Get-Service -Name $name -Computername $server -ErrorAction SilentlyContinue -ErrorVariable WindowsServiceExistsError)
{
Write-Host "$name Exists on $server"
return $true
}
if ($WindowsServiceExistsError)
{
Write-Host "$server" $WindowsServiceExistsError[0].exception.message
}
return $false
}
As for the second part of the question #arco444 has described the correct approach.
Here's a WMI solution. Any errors you get from attempting to connect to remote computers will be caught with the try/catch blocks. The result of each operation will be stored to a custom object and added to the array that holds the results of all the operations.
$result = #()
$name = "BESClient"
$servers = Get-Content C:\list.txt
$cred = Get-Credential
foreach($server in $servers) {
Try {
$s = gwmi win32_service -computername $server -credential $cred -ErrorAction Stop | ? { $_.name -eq $name }
$o = New-Object PSObject -Property #{ server=$server; status=$s.state }
$result += ,$o
}
Catch {
$o = New-Object PSObject -Property #{ server=$server; status=$_.Exception.message }
$result += ,$o
}
}
$result | Format-Table -AutoSize
You should end up with something like this:
server state
------ -----
s1 running
s4 stopped
s2 The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)