I'm trying to log ping results if the response doesnt have a reply
My final line is essentially this and I'm wondering how I can capture and log lines that do not get a valid response.
Ping.exe -t 8.8.8.8 | ForEach{"{0}-{1}"-f(Get-Date),$_} > "C:\Users\test.txt"
Any pointers as to how about I could filter those responses?
You could do something like this:
param(
$ip = '8.8.8.9',
$shouldExecute = $true,
$logFile = "$PSScriptRoot\log.txt"
)
while ($shouldExecute -eq $true) {
$result = Test-NetConnection -ComputerName $ip -InformationLevel "Detailed"
if ($result.PingSucceeded -eq $false) {
"$(Get-Date) | IP: $($result.ComputerName) | Ping Succeeded: $($result.PingSucceeded)" `
| Out-File -Append $logFile -Verbose
}
}
function Show-Menu{
param([string]$Title = 'Server Selection')
Clear-Host
Write-Host "$Title"
Write-Host "1) Remote Server 1"
Write-Host "2) Remote Server 2"}
function Show-Menu1{
param([string]$Title = 'Server Selection')
Clear-Host
Write-Host "$Title"
Write-Host "1) Local Connection 1"
Write-Host "2) Local Connection 2"}
$user = $env:USERNAME
Show-Menu1 -Title 'Local Server Selection'
$Selection1 = Read-Host "Please Make a Selection"
switch($Selection1){
1{$LocalServer = "Server1"}
2{$LocalServer = "Server2"}}
Show-Menu1 -Title 'Remote Server Selection'
$Selection = Read-Host "Please Make a Selection"
switch($Selection){
1{$RemoteServer = "8.8.8.8"} #Google DNS
2{$RemoteServer = "8.8.4.4"}}
$today = (Get-Date).ToString('MM_dd_yy')
$basedir = "C:\Users\$user\Logs\$LocalServer\$RemoteServer\$today"+".txt"
Write-Host "Running Remote Test on $RemoteServer From $LocalServer Press <CTRL> + <C> to Stop"
$shouldExecute = $true
while ($shouldExecute -eq $true){
$Result = Test-NetConnection $RemoteServer -InformationLevel "Detailed"
if($Result.PingSucceeded - $false){
"$(Get-Date) | Remote: $($Result.ComputerName) | Ping Succeeded: $($Result.PingSucceeded) | From: $($LocalServer) | By: $($user)" | Out-File -Append $basedir -Verbose}
$today = (Get-Date).ToString('MM_dd_yy')
$basedir = "C:\Users\$user\Logs\$LocalServer\$RemoteServer\$today"+".txt"}
Related
The script below is currently configured to perform Qwinsta from multiple online servers, and then send the result as email.
$Today = Get-Date -Format 'F'
$SessionList = "`n`nRDP Session List - " + $Today + "`n`n"
$CurrentSN = 0
# Get a list of servers from Active Directory
write-progress -activity "Getting list of servers from Active Directory" -status "... please wait ..."
$Servers = Get-ADComputer -Filter { Enabled -eq $True -and OperatingSystem -like "*Server*" } -SearchBase "OU=servers,dc=dwlab02,dc=local" | Where-Object { Test-Connection $_.Name -Count 1 -Quiet } | Select-Object -ExpandProperty Name
$NumberOfServers = $Servers.Count
# Iterate through the retrieved list to check RDP sessions on each machine
ForEach ($Server in $Servers) {
$ServerName = $Server.Name
Write-progress -activity "Checking RDP Sessions" -status "Querying $ServerName" -percentcomplete (($CurrentSN / $NumberOfServers) * 100)
# Run qwinsta and grab the output
try {
$queryResults = (qwinsta /server:$ServerName | Select-Object -Skip 1 | ForEach-Object { (($_.trim() -replace "\s+", ",")) } | convertfrom-csv -ErrorAction Stop)
# get session info from the instance
ForEach ($QueryResult in $QueryResults) {
$RDPUser = $($QueryResult.substring(19, 22)).trim()
$SessionType = $($QueryResult.substring(1, 18)).trim()
$SessionID = $($QueryResult.substring(41, 5)).trim()
$ReturnedCurrentState = $($QueryResult.substring(48, 8)).trim()
$RDPUser = $QueryResult.USERNAME
$SessionType = $QueryResult.SESSIONNAME
$SessionID = $QueryResult.ID
$ReturnedCurrentState = $QueryResult.State
If ($ReturnedCurrentState -eq $null) { $CurrentState = "Disconnected" } Else { $CurrentState = "Active" }
# filter out the irrelevant information
If (($RDPUser -ne $NULL) -and ($SessionType -ne "console") -and ($SessionType -ne "services") -and ($SessionType -ne "rdp-tcp") -and ($RDPUser -ne "65536")) {
$SessionList = $SessionList + "`n" + $ServerName + " logged in by " + $RDPUser + " on " + $SessionType + ", session id $SessionID $CurrentState"
}
}
}
catch {
$SessionList = $SessionList + "`n Unable to query " + $ServerName
write-host "Unable to query $ServerName!" -foregroundcolor Red
}
$CurrentSN++
}
# Send the output the screen.
$SessionList + "`n`n"
$sendMailArgs = #{
From = 'sender#domain.com'
To = 'recipient#domain.com'
Subject = "$($SessionList.Count) Logged On users from $($NumberOfServers) online servers as at $($Today)"
SmtpServer = 'smtp.office365.com'
Port = 587
UseSsl = $true
Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username, (ConvertTo-SecureString -String $Password)
}
Send-MailMessage #sendMailArgs -Body $SessionList
However, the result is always a blank email with the below content:
RDP Session List - Monday, 17 August 2020 12:28:19 PM
Unable to query Unable to query Unable to query Unable to query
Unable to query Unable to query Unable to query Unable to query
Unable to query
How can I fix the above script?
I wrote a few lines of code to check if a port is open or not:
$ports = #(5353,5672,8080,4443,15672,9200)
foreach ($port in $ports)
{
TNC -ComputerName localhost -Port $port -InformationLevel Quiet -WarningAction SilentlyContinue | Tee-Object -Variable CheckPortStatus > $null
if ($CheckPortStatus -eq "True")
{$status = Write-Host "Open" -ForegroundColor GREEN}
else
{$status = Write-Host "close" -ForegroundColor RED}
echo "the port is $status"
I don't get why the output is this:
The script actually works but it execute the variable when declared and then it doesn't use the variable after the if/else
The Write-Host cmdlet just prints something to the console, it doesn't return anything so you can't assign it to $status. Instead you should do something like this:
$ports = #(5353,5672,8080,4443,15672,9200)
foreach ($port in $ports)
{
TNC -ComputerName localhost -Port $port -InformationLevel Quiet -WarningAction SilentlyContinue | Tee-Object -Variable CheckPortStatus > $null
if ($CheckPortStatus -eq "True")
{
$status = "Open"
Write-Host $status -ForegroundColor GREEN
}
else
{
$status = "Closed"
Write-Host $status -ForegroundColor RED
}
Write-Host "the port is $status"
}
Quote from Jeffrey Snover:
When you are writing or reviewing PowerShell scripts, I’d like you to
remember the following rule of thumb:
Using Write-Host is almost always wrong.
Im trying to get this script to work by instead of me manually inputing sysnames that I can put the servers into csv and script it and give an output of results
It just sits at the prompt waiting for manual input
$csvpath = E:\Tsm.csv
$SvcName = '*tsm*scheduler*'
$dataset = import-csv -path $csvpath
$row = ($dataset | where{$_.hostname -eq $SysName})
$SysName = Read-Host -prompt "Enter the target computer name: "
$Tsm = Get-Service -ComputerName $SysName | Where {$_.name -Like $SvcName}
Write-Host "Service :" $Tsm.DisplayName
Write-Host "Status :" $Tsm.Status
Write-host "Start Type :" $Tsm.StartType
If ($Tsm.StartType -ne 'Automatic')
{
Write-Host "Setting service startup type to Automatic."
Set-Service -InputObject $Tsm -StartupType Automatic
}
If ($Tsm.Status -ne 'Running')
{
Write-Host "Starting the service."
Start-Service -InputObject $Tsm
}
$Tsm2 = Get-Service -ComputerName $SysName | Where {$_.name -Like $SvcName}
Write-Host "Service :" $Tsm2.DisplayName
Write-Host "Status :" $Tsm2.Status
Write-host "Start Type :" $Tsm2.StartType
Export-Csv C:\TestOutput.csv$csvpath = E:\Tsm.csv
There are many ways to get what you want. Basically you shouldn't be using Read-Host, or only use it when you want the prompt and manual waiting.
A couple of points:
# this line uses the $SysName variable, which is asked for in the next line.
# so it will not work correctly.
$row = ($dataset | where{$_.hostname -eq $SysName})
# if you do not want the waiting and pause on screen, remove this line.
# That's the standard way Read-Host works.
$SysName = Read-Host -prompt "Enter the target computer name: "
One possible solution:
param(
[switch]$manual
)
if($manual){
$SysName = Read-Host -prompt "Enter the target computer name: "
}else{
$SysName = "value or variable"
}
With this solution you can call your script using .\script.ps1 for auto-solution or .\script.ps1 -manual for the Read-Host.
I am making a menu using a switch statement with options 1-9. The options are:
report computer name and the os version,
report on disk space,
report on folderspace for a specified folder,
create a folder and copy all text files from a folder,
create local user and
start or stop a service.
set IP address,
test connectivity to a machine,
exit.
I already have it working on a local machine but I would like to be able to use the options 1-6 on a remote machine. I am not sure how to do this.
do
{
Show-Menu
$input = Read-Host "Select 1-9"
switch ($input)
{
'1' {
cls
Write-Host -NoNewLine "OS Version: "
Get-CimInstance Win32_OperatingSystem | Select-Object Caption | ForEach{ $_.Caption }
Write-Host ""
Write-Host -NoNewLine "Computer Name: "
Get-CimInstance Win32_OperatingSystem | Select-Object CSName | ForEach{ $_.CSName }
Write-Host ""
} '2' {
cls
gwmi win32_logicaldisk | Format-Table DeviceId, MediaType, #{n="Size";e={[math]::Round($_.Size/1GB,2)}},#{n="FreeSpace";e={[math]::Round($_.FreeSpace/1GB,2)}}
} '3' {
$Path = Read-Host -Prompt 'Please enter the folder name:'
if($Path) {
Write-Host "string is not empty"
}
$colItems = Get-ChildItem $Path | Where-Object {$_.PSIsContainer -eq $true} | Sort-Object
foreach ($i in $colItems)
{
$subFolderItems = Get-ChildItem $i.FullName -recurse -force | Where-Object {$_.PSIsContainer -eq $false} | Measure-Object -property Length -sum | Select-Object Sum
$i.FullName + " -- " + "{0:N2}" -f ($subFolderItems.sum / 1MB) + " MB"
}
else {
Write-Host "String is EMPTY or NULL"
}
}'4' {
cls
# Specify the path
$destDir = Read-Host -Prompt 'Please enter the new folder name: '
#check that input is not empty
if($destDir) {
Write-Host "string is not empty"
}
else {
Write-Host "String is EMPTY or NULL"
}
# Check if the folder exist if not create it
$dir = $destDir
if(!(Test-Path -Path $dir )){
New-Item -ItemType directory -Path $dir
Write-Host "New folder created"
}
else
{
Write-Host "Folder already exists"
}
# Check if the folder exist if not create it
If (!(Test-Path $destDir)) {
md $dir
}
$sourceDir=Read-Host -Prompt 'Please enter the folder you want to copy files from: '
Copy-Item -path $sourceDir\*.txt -Destination $destDir
Write-Host "Text files copied to $destDir"
} '5' {
cls
$Computername = $env:COMPUTERNAME
$ADSIComp = [adsi]"WinNT://$Computername"
$Username = 'TestProx'
$Username = Read-Host -Prompt 'Please enter the New User'
$NewUser = $ADSIComp.Create('User',$Username)
#Create password
$Password = Read-Host -Prompt "Enter password for $Username" -AsSecureString
$BSTR = [system.runtime.interopservices.marshal]::SecureStringToBSTR($Password)
$_password = [system.runtime.interopservices.marshal]::PtrToStringAuto($BSTR)
#Set password on account
$NewUser.SetPassword(($_password))
$NewUser.SetInfo()
}'6' {
cls
$Display = Read-Host -Prompt 'Please enter service name: '
if($Display) {
Write-Host "string is not empty"
$Choice = Read-Host -Prompt 'Would you like to start or stop the service'
If ($Choice -eq 'start') {
Start-Service -displayname $Display
Write-Host $Display "Starting..." -ForegroundColor Green
}
If ($Choice -eq 'stop') {
Stop-Service -displayname $Display
Write-Host $Display "Stopping..." -ForegroundColor Green
}
}
else {
Write-Host "String is EMPTY or NULL"
}
}'7' {
cls
$IP = Read-Host -Prompt 'Please enter the Static IP Address. Format 192.168.x.x'
$MaskBits = 24 # This means subnet mask = 255.255.255.0
$Gateway = Read-Host -Prompt 'Please enter the defaut gateway IP Address. Format 192.168.x.x'
$Dns = Read-Host -Prompt 'Please enter the DNS IP Address. Format 192.168.x.x'
$IPType = "IPv4"
# Retrieve the network adapter that you want to configure
$adapter = Get-NetAdapter | ? {$_.Status -eq "up"}
# Remove any existing IP, gateway from our ipv4 adapter
If (($adapter | Get-NetIPConfiguration).IPv4Address.IPAddress) {
$adapter | Remove-NetIPAddress -AddressFamily $IPType -Confirm:$false
}
If (($adapter | Get-NetIPConfiguration).Ipv4DefaultGateway) {
$adapter | Remove-NetRoute -AddressFamily $IPType -Confirm:$false
}
# Configure the IP address and default gateway
$adapter | New-NetIPAddress `
-AddressFamily $IPType `
-IPAddress $IP `
-PrefixLength $MaskBits `
-DefaultGateway $Gateway
# Configure the DNS client server IP addresses
$adapter | Set-DnsClientServerAddress -ServerAddresses $DNS
}'8' {
cls
$Server = Read-Host -Prompt 'Please enter server name.'
if (Test-Connection $Server -Count 1 | Out-Null) { write-host "true" } else {write-host "false"}
}'9' {
return
}
}
pause
}
until ($input -eq '9')
The simplest way to perform remote execution is with PSSession:
Enter-PSSession remote_server_name
ls #returns results on remote server
Exit-PSSession
You could also use Invoke-Command:
Invoke-Command remote-server-name { ls }
So here's the scope of what I'm trying to do:
Get remote computer information for Windows computers in multiple sites and write the information found to the .Description property of each computer object in Active Directory. If the script can't connect to the remote machine, log that information into a text file and don't make any changes to the computer object that can't be connected to.
In order to time how long the script is taking to run, I have a second script that measures the execution time.
I have this setup as a scheduled task to run the second script (which calls the first) that is executed via a batch file on a Windows 7 Pro virtual machine.
My problem is I believe the script may be running into memory problems based on the information I see in my log. Any help on possible diagnosing the root cause would be appreciated to the extreme. Without further adieu, here's my code for both scripts as well as a sample of the strange log output.
Main Script (script 1):
set-location \\myscriptcomputer\c$\somefolder\PSScripts
enter code here`function Measure-Latest {
BEGIN { $latestlogon = $null }
PROCESS {
if (($_ -ne $null) -and (($latestlogon -eq $null) -or ($_ -gt $latestlogon))) {
$latestlogon = $_
}
}
END { $latestlogon }
}
Function CreateLog {
#Create a log file
$global:path = "C:\Somefolder\PSScripts\WriteComputerDescriptions"
$global:LogTime = Get-Date -Format "MM-dd-yyyy_hh-mm-ss"
$global:LogName = 'CompDescriptions'
$global:LogFile = 'C:\Somefolder\PSScripts\WriteComputerDescriptions\'+$LogName+$LogTime+'.txt'
Write-Host "Creating log file" -foregroundcolor yellow
if([IO.Directory]::Exists($global:path))
{
#Do Nothing
}
else
{
New-Item -ItemType directory -Path C:\Somefolder\PSScripts\WriteComputerDescriptions
}
cd C:\Somefolder\PSScripts\WriteComputerDescriptions
echo "WriteComputerDescriptions Script Log" >> $global:logfile
}
Function WriteDescription {
Write-Host "Gathering Computer information..." -foregroundcolor yellow
$UserWorkstations = get-qadcomputer -sizelimit 0 -includeallproperties -searchroot my.domain.com/MyUserWorkstations
$IPv4Regex = "^(\d{1,3}\.){3}\d{1,3}$"
foreach ($computerobject in $UserWorkstations) {
$computerIP = $NULL
$computerIP2 = $NULL
$computerIP3 = $NULL
$computerserial = $NULL
$computerserial2 = $NULL
$findlastuser = $NULL
$findlastuser2 = $NULL
$lastlogontime = $NULL
$findlastuserFname = $NULL
$findlastuserFname2 = $NULL
$findlastuserLname = $NULL
$findlastuserLname2 = $NULL
$fullname = $NULL
$userlogon = $NULL
$computerName = $computerobject.name
$oldcomputerdescription = $computerobject.description
Write-Host " "
Write-Host "Testing connection to $computerName ..."
$testConnection = test-connection -computername $computerName -count 2 -quiet
Write-Host "Connection is $testconnection"
if ($testConnection -eq $True) {
$Connect = $testConnection
#get IP address(es)
try {
$computerIP = get-wmiobject -class win32_networkadapterconfiguration -filter IPEnabled=TRUE -computername $computerName
$computerIP2 = $computerIP.ipaddress[0]
$computerIP3 = $computerIP.ipaddress[1]
Write-Host = $computerIP2
if ($computerIP3 -match $IPv4Regex){
Write-Host = $computerIP3
}
}
catch [system.exception]{
$connect = $False
Write-Host "Could not connect to $computerName. No IP collected."
}
#get computer serial
try {
$computerSerial = gwmi win32_bios -computername $computerName | select serialnumber
$computerserial2 = $computerSerial.serialnumber.tostring()
}
catch [system.exception]{
Write-Host "Could not get serial for $computerName."
$computerSerial = "Unavailable"
$computerSerial2 = "Unavailable"
}
#get username of currently logged in user
try {
$findlastUser = gwmi win32_computersystem -computer $computerName | select username
$findlastuser2 = ($findlastUser.username).replace("mydomain\","")
}
catch [system.exception]{
Write-Host "Could not get username of logged in user on $computerName"
$findlastUser = "Unavailable"
$findlastUser2 = "Unavailable"
}
#get last logon time of user
try {
if($findlastuser2 -ne $NULL -and $findlastuser2 -notlike "Unavailable") {
#ignore domain controllers in a datacenter due to connectivity stuff
$lastlogontime = get-qadcomputer -computerrole domaincontroller | where { $_.name -notmatch "-COLO"} | foreach {(get-qaduser -service $_.name -samaccountname $findlastuser2).LastLogon } | Measure-Latest
}
}
catch {
if ($lastlogontime -eq $NULL -and $findlastuser2 -eq $NULL){
Write-Host "Could not find a last logon time"
Write-Host "No username available to query"
$lastlogontime = "Unavailable"
}
if ($lastlogontime -eq $NULL -and $findlastuser2 -ne $NULL){
Write-Host "Could not find a last logon time for user $findlastuser"
$lastlogontime = "Unavailable"
}
}
#search AD for the user identified, select first name
try {
$findlastuserFname = get-qaduser $findlastuser2 | select firstname
$findlastuserFname2 = $findlastuserFname.firstname.tostring()
}
catch [system.exception]{
if ($findlastuserFname2 -eq $NULL) {
Write-Host "No first name for user found"
}
}
#search AD for the user identified, select last name
try {
$findlastuserLname = get-qaduser $findlastuser2 | select lastname
$findlastuserLname2 = $findlastuserLname.lastname
}
catch [system.exception] {
if ($findlastuserLname2 -eq $NULL) {
Write-Host "No last name for user found"
}
}
#join the first and last names together if both properties are available
if ($findlastuserFname2 -ne $NULL -and $findlastuserLname2 -ne $NULL){
$fullname = "$findlastuserFname2" + " $findlastuserLname2"
}
elseif ($findlastuserFname2 -eq $NULL -and $findlastuserLname -ne $NULL){
$fullname = $findlastuserLname2
}
elseif ($findlastuserFname2 -ne $NULL -and $findlastuserLname -eq $NULL){
$fullname = $findlastuserFname2
}
else {
$fullname = "Unavailable"
}
#Set the description data format
#With only 1 IPv4 Address
if ($computerIP3 -notmatch $IPv4Regex -or $computerIP3 -eq $NULL){
$newcomputerdescription = "$fullname | $computerIP2 | $computerSerial2 | $lastlogontime"
}
#With 2 IPv4 Addresses
if ($computerIP3 -match $IPv4Regex) {
$newcomputerdescription = "$fullname | $computerIP2, $computerIP3 | $computerSerial2 | $lastlogontime"
}
#If the description data is the same, leave it as it is
if ($newcomputerdescription -eq $oldcomputerdescription){
Write-Host " "
Write-Host "Information for $computerName has not" -foregroundcolor yellow
Write-Host "changed. No edits were made on this object." -foregroundcolor yellow
}
if ($newcomputerdescription -ne $oldcomputerdescription -and $Connect -eq $TRUE) {
set-qadcomputer -identity $computerName -Description $newcomputerdescription
Write-Host " "
Write-Host "Computer description updated for object $computerName" -foregroundcolor yellow
Write-Host "New host information:"
Write-Host "$newcomputerdescription"
}
}
else {
Write-Host "Could not connect to computer $computerName"
Write-Host "No changes made to description for $computerName"
$noconnecterror = "Could not connect to computer $computerName"
$noconnecterror | Out-File $global:logfile -Append -Force
}
}
Write-Host "Processing complete!"
}
CreateLog -erroraction silentlycontinue
WriteDescription -erroraction silentlycontinue
start-sleep -s 3
##END OF SCRIPT
Second Script:
set-location \\myscriptcomputer\c$\somefolder\PSScripts
Add-PSSnapin Quest.ActiveRoles.ADManagement -erroraction SilentlyContinue
$timeoutput = Measure-Command {\\myscriptcomputer\c$\Somefolder\PSScripts\WriteComputerDescriptions.ps1}
cd \\myscriptcomputer\c$\Somefolder\PSScripts\WriteComputerDescriptions
$scriptlog = get-childitem | sort creationtime | select -last 1
$logname = $scriptlog.name
Add-Content c:\somefolder\PSScripts\WriteComputerDescriptions\$logname "`nExecution Time: $timeoutput"
Write-Host "Script complete!"
Start-sleep -s 3
exit
In the results in my environments Active Directory, this works effectively for several hundred objects, but here's a sample of what I see in my log file:
Could not connect to computer computer391
Could not connect to computer computer392
Could not connect to computer computer393
Could not connect to computer computer394
䔊數畣楴湯吠浩㩥ㄠ㨱㘰㈺⸱㜵㤵㐰ഷ
The very last line with the garbled text is what made me think there's a memory-related issue perhaps. If I run my scripts against a container/OU with a much smaller amount of computers, the last line in my log is a time, which is what I would normally expect.
If any seasoned Powershell pros could offer some advice here, I'd really appreciate the help.
Thanks!
I don't know why my comments are not getting added. Anyways, let me just post it here.
In order to track the free memory, you just look at its the performance counter.
Here is the powershell command:
Get-Counter -Counter "\Memory\Available MBytes"