I'm working on a little script to gather some wisdom and options in one script. For later and for myself. It's a simple one but with lot of informations and "reusability".
I'm now trying to achive a jump in an "running" process of a list. All I could think of till now is to achive this via regex. But I can barley use regex properly.
#Custom Ping to identify the scenario
function Custom-Ping {
Param(
[string]$Address
)
$ping = ping $Address /w 1 /n 1
if (![string]::IsNullOrEmpty($ping -Like "*(100% loss)*")) {
$result = "Error"
} elseif(![string]::IsNullOrEmpty($ping -Like "*expired*")) {
$result = "Warning"
} else {
$result = "succeded"
}
return $result
}
$ErrorActionPreference = "SilentlyContinue"
$tstart = Get-Date
$counter = 0
$unreachable = 0
$IPlist = foreach ($Network in 1..29) {
foreach ($Range in 1..254) {
"10.10.$Network.$Range"
}
}
foreach ($IP in $IPlist) {
$counter ++
try {
if ($unreachable -lt 6) {
#SwitchCase
$case = Custom-Ping $IP
switch ($case) {
succeded {
Write-Host "Response from: $IP" -ForegroundColor Green
#$IP | Export-Csv -Path D:\somepath.csv -Append
}
Error {
Write-Host "No Response from: $IP" -ForegroundColor Red
#$IP | Export-Csv -Path D:\somepath.csv -Append
}
Warning {
Write-Host "Time Expired on: $IP" -ForegroundColor Yellow
#$IP | Export-CSV -path D:\somepath.csv -Append
$unreachable ++
}
default {
Write-Warning "An Error Occured while processing"
}
}
} else {
#Hop to the next range as this range isnt accesibble
#$IPswap = $IP
#newIP = $Ipswap "$Network from 2 to 3"
#$IP=$newIP
$unreachable = 0
Write-Host "The Network xxxx cant be reached"
}
} catch {
Write-Warning "Other Error"
}
}
$tend = Get-Date
Write-Host "$counter Completed Ping requests"
New-TimeSpan -Start $tstart -End $tend | select Minutes, Seconds
This is the script so far... I didn't find a way till now to achive this jump of the "network".
For Example it got 5 unreachable in 10.10.2.0 network and then sets to 10.10.3.0 network and starts there again with the process.
I was wondering if this is even possible in this scenario.
Use nested loops and labels instead:
:Network # Now we can jump into the next iteration of this loop from an inner loop
foreach ($Network in 0..29)
{
:Host
foreach($Node in 0..254){
$IP = "10.10.$Network.$Node"
#Counter for "Statistic"
$counter ++
try
{
#Check error sum for Range Hop
if($unreachable -lt 6)
{
#SwitchCase
$case = Custom-Ping $IP
switch ($case)
{
succeded
{
Write-Host "Response from: $IP" -ForegroundColor Green
#$IP | Export-Csv -Path D:\somepath.csv -Append
}
Error
{
Write-Host "No Response from: $IP" -ForegroundColor Red
#$IP | Export-Csv -Path D:\somepath.csv -Append
}
Warning
{
Write-Host "Time Expired on: $IP" -ForegroundColor Yellow
#$IP | Export-CSV -path D:\somepath.csv -Append
$unreachable ++
}
default
{
Write-Warning "An Error Occured while processing"
}
}
}
else
{
$unreachable = 0
Write-Host "The Network 10.10.$Network.0/24 cant be reached, jumping to 10.10.$($Network + 1).0/24"
# jump forward to the next iteration of the outer "Network" loop
continue Network
}
}
catch
{
Write-Warning "Other Error"
}
}
}
Related
Trying to use PowerShell to capture the running status of the "Nessus Essentials" software product. Simply trying to capture product status: running, not running, or other. Getting the below error each time. I've tried changing -like to -match and changing string [warn] [scanner] Not linked to a manager to various other shorter versions, with wildcards and without, to no avail. I still get several lines of an ugly error message when all I want is one line with the string Not linked to a manager returned to console with nothing beneath that.
Pertinent snippet working incorrectly:
} elseif(($agentStatus.stdOut -like "[warn] [scanner] Not linked to a manager")) {
Throw "Not linked to a manager"
The Error:
The Code:
Function Start-ProcessGetStreams {
[CmdLetBinding()]
Param(
[System.IO.FileInfo]$FilePath,
[string[]]$ArgumentList
)
$pInfo = New-Object System.Diagnostics.ProcessStartInfo
$pInfo.FileName = $FilePath
$pInfo.Arguments = $ArgumentList
$pInfo.RedirectStandardError = $true
$pInfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pInfo.CreateNoWindow = $true
$pInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo = $pInfo
Write-Verbose "Starting $FilePath"
$proc.Start() | Out-Null
Write-Verbose "Waiting for $($FilePath.BaseName) to complete"
$proc.WaitForExit()
$stdOut = $proc.StandardOutput.ReadToEnd()
$stdErr = $proc.StandardError.ReadToEnd()
$exitCode = $proc.ExitCode
Write-Verbose "Standard Output: $stdOut"
Write-Verbose "Standard Error: $stdErr"
Write-Verbose "Exit Code: $exitCode"
[PSCustomObject]#{
"StdOut" = $stdOut
"Stderr" = $stdErr
"ExitCode" = $exitCode
}
}
Function Get-NessusStatsFromStdOut {
Param(
[string]$stdOut
)
$stats = New-Object System.Collections.Hashtable
$StdOut -split "`r`n" | % {
if($_ -like "*:*") {
$result = $_ -split ":"
$stats.add(($result[0].Trim() -replace "[^A-Za-z0-9]","_").ToLower(),$result[1].Trim())
}
}
Return $stats
}
Function Get-DateFromEpochSeconds {
Param(
[int]$seconds
)
$utcTime = (Get-Date 01.01.1970)+([System.TimeSpan]::fromseconds($seconds))
Return Get-Date $utcTime.ToLocalTime() -Format "yyyy-MM-dd HH:mm:ss"
}
Try {
$nessusExe = Join-Path $env:ProgramFiles -ChildPath "Tenable\Nessus\nessuscli.exe" -ErrorAction Stop
} Catch {
Throw "Cannot find NessusCli.exe"
}
Write-Host "Getting Agent Status..."
$agentStatus = Start-ProcessGetStreams -FilePath $nessusExe -ArgumentList "managed status"
If($agentStatus.stdOut -eq "" -and $agentStatus.StdErr -eq "") {
Throw "No Data Returned from NessusCli"
} elseif($agentStatus.StdOut -eq "" -and $agentStatus.StdErr -ne "") {
Throw "StdErr: $($agentStatus.StdErr)"
} elseif(($agentStatus.stdOut -like "[warn] [scanner] Not linked to a manager")) {
Throw "Not linked to a manager"
} elseif(-not($agentStatus.stdOut -like "*Running: *")) {
Throw "StdOut: $($agentStatus.StdOut)"
} else {
$stats = Get-NessusStatsFromStdOut -stdOut $agentStatus.StdOut
If($stats.last_connection_attempt -as [int]) { $stats.last_connection_attempt = Get-DateFromEpochSeconds $stats.last_connection_attempt }
If($stats.last_connect -as [int]) { $stats.last_connect = Get-DateFromEpochSeconds $stats.last_connect }
If($stats.last_scanned -as [int]) { $stats.last_connect = Get-DateFromEpochSeconds $stats.last_scanned }
}
$stats | Out-Host
Note: Code above is courtesy of here, I've only made a change to the path of Nessus, and I am adding the attempt to capture that it's not connected to a manager.
Modify your code so that it separates standard output from error and so that it handles each line separately.
The following is how to capture standard output (excluding else statements and error handling) of a program (according to your $Proc variable)
if ($proc.Start())
{
while (!$proc.StandardOutput.EndOfStream)
{
$StreamLine = $proc.StandardOutput.ReadLine()
if (![string]::IsNullOrEmpty($StreamLine))
{
# TODO: Duplicate code in this scope as needed or rewrite to use multiline regex
$WantedLine = [regex]::Match($StreamLine, "(?<wanted>.*Not linked to a manager.*)")
$Capture = $WantedLine.Groups["wanted"]
if ($Capture.Success)
{
Write-Output $Capture.Value
}
}
}
}
After that deal with error output separately:
$StandardError = $Proc.StandardError.ReadToEnd()
if (![string]::IsNullOrEmpty($StandardError))
{
# Or use Write-Error
Write-Output $StandardError
}
using below snippet :
#loop until we have found the newly added domain
$Stop=''
while (-not $Stop)
{
$stop = Get-AzureADDomain -Name $direct_routing_domain -ErrorAction Ignore | Out-Null
if (!$stop)
{
Write-Host "Domain is not provisioned yet - retrying in 60 seconds..." -ForegroundColor Yellow
Start-Sleep -Seconds 60
}
}
Write-Host "Domain is provisioned " -ForegroundColor Green
The output gives an error on stdout:
Get-AzureADDomain : Error occurred while executing GetDomain
Code: Request_ResourceNotFound
...
So here comes the question: how can I surpress this output ? I believe that | out-null should be enough. Or is this a bug in AzureAd 2.0.0 module ?
Out-Null does not ignore errors. Out-Null redirects stdout (known as stream #1) to null. You can try doing a try catch (catch provides easy exceptions handling)
try {}
catch {}
doc. https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-5.1
or redirect an error stream to void
Write-Error "ASD" 2>$null
doc. https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection?view=powershell-5.1
You can use this:
$stop = $true
try {Get-AzureADDomain -Name $direct_routing_domain}
catch {
$stop = $false
}
OR
$stop = $true
$domain = Get-AzureADDomain | Where-Object {$_.Name -eq $direct_routing_domain}
if ($null -eq $domain) {
$stop = $false
}
You can use a try{}..catch{} on this, but remember to add -ErrorAction Stop (not 'Ignore') to the cmdlet to ensure also non-terminating exceptions are caught in the catch block:
# loop until we have found the newly added domain
$isProvisioned = $false
while (-not $isProvisioned) {
try {
$isProvisioned = [bool](Get-AzureADDomain -Name $direct_routing_domain -ErrorAction Stop)
}
catch { $isProvisioned = $false }
if (!$isProvisioned) {
Write-Host "Domain is not provisioned yet - retrying in 60 seconds..." -ForegroundColor Yellow
Start-Sleep -Seconds 60
}
}
Write-Host "Domain is provisioned " -ForegroundColor Green
I create script for check available resources:
$servers = New-Object System.Collections.Generic.Dictionary"[String,String]"
$servers.Add("Server 1","127.0.0.1")
$servers.Add("Server 2","127.0.0.1")
$servers.Add("Server 3","127.0.0.1")
$virtuals = New-Object System.Collections.Generic.Dictionary"[String,String]"
$virtuals.Add("VM 1","127.0.0.1")
$virtuals.Add("VM 2","127.0.0.1")
$virtuals.Add("VM 3","127.0.0.1")
Write-Output("`n")
Write-Output("Check availiable servers")
foreach ($key in $servers.GetEnumerator()){
if ((Test-Connection $key.Value -Count 3 -Quiet)){
[pscustomobject]#{Server = $key.Key; Status = "Availiable"}
}else{
[pscustomobject]#{Server = $key.Key; Status = "Not availiable"}
}
}
Remove-Variable -Name [pscustomobject]
Write-Output("`n")
Write-Output("Check availiable virtuals")
Write-Output("`n")
foreach ($key in $virtuals.GetEnumerator()){
if ((Test-Connection $key.Value -Count 3 -Quiet)){
[pscustomobject]#{VM = $key.Key; Status = "Availiable"}
}else{
[pscustomobject]#{VM = $key.Key; Status = "Not availiable"}
}
}
If I change the title, then the output is in the following table without the first column. And I can't find how I can print the title in every new cycle? My ultimate goal is to have a header for each new loop and color-coded available and unavailable addresses.
If by 'elegant' you mean outputting a line in the table in some color, depending on availability, use something like this:
$servers = [ordered]#{
"Server 1" = "127.0.0.1"
"Server 2" = "127.0.0.1"
"Server 3" = "127.0.0.1"
}
$virtuals = [ordered]#{
"VM 1" = "127.0.0.1"
"VM 2" = "127.0.0.1"
"VM 3" = "127.0.0.1"
}
Write-Host "Check available servers" -ForegroundColor Cyan
$svr = foreach ($key in $servers.GetEnumerator()){
if ((Test-Connection $key.Value -Count 3 -Quiet)){
[pscustomobject]#{Server = $key.Key; Status = "Available"}
}
else{
[pscustomobject]#{Server = $key.Key; Status = "Not available"}
}
}
# output this as colored table
$svr | Format-Table | Out-String -Stream | ForEach-Object {
$color = if ($_ -match 'Not available') { 'Red' } else { 'Green' }
Write-Host $_ -ForegroundColor $color
}
Write-Host
# now do the same for the VMs
Write-Host "Check available virtuals" -ForegroundColor Cyan
$vms = foreach ($key in $virtuals.GetEnumerator()){
if ((Test-Connection $key.Value -Count 3 -Quiet)){
[pscustomobject]#{VM = $key.Key; Status = "Available"}
}
else{
[pscustomobject]#{VM = $key.Key; Status = "Not available"}
}
}
# output this as colored table
$vms | Format-Table | Out-String -Stream | ForEach-Object {
$color = if ($_ -match 'Not available') { 'Red' } else { 'Green' }
Write-Host $_ -ForegroundColor $color
}
Output:
As PowerShell has already added the titles to the tops of the columns from the previous item, it doesn't add them again. Part of its way to reduce repetition or something probably.
You could maybe do an output using Write-Host and then you can format to your hearts content.
Write-Host "Servers" -ForegroundColor Cyan
Write-Host "Virtuals" -ForegroundColor Cyan
You could also do something like...
if ($status -eq "Available") {
$color = "Green"
} else {
$color = "Red"
}
Then when you come to write your results you could do...
Write-Host "Server Name" -ForegroundColor $color
Hope that makes sense, I can write something out fully if you need.
$topDC1="10.254.90.17"
$topDC2="10.225.224.17"
$topDC3="10.110.33.32"
$topDC4="10.88.100.10"
$DomainName="office.adroot.company.net"
TRY{
$hostname = [System.Net.DNS]::GetHostByName($topDC1).HostName.toupper()
$ipaddress = [System.Net.Dns]::GetHostAddresses($DomainName) | select IPAddressToString -ExpandProperty IPAddressToString
# I want the below to loop foreach ip in the object, ns it against all 4 topDC's, then output each result :(
$NS1 = nslookup $ipaddress[0] $topDC1
Write-host $NS1
}
Catch{
write-host "error"
}
Here is my dirty code so far (just to keep it simple)
I am trying to automate this:
NSLOOKUP office.adroot.company.net
put the results into an object
for each ip in results, do an NSLOOKUP against our top level DC's.
find which DC's haven't been cleaned up after decommission (still in dns)
$DCList="10.254.90.17","10.225.224.17","10.110.33.32","10.88.100.10"
$DomainName="office.adroot.blorg.net","pcd.blorg.ca","blorg.ca","percom.adroot.blorg.net", "blorg.blorg.net","ibg.blorg.net","sacmcm.adroot.blorg.net","sysdev.adroot.blorg.net","adroot.blorg.net"
TRY{
foreach ($DomainNameItem in $DomainName){
Write-Host ""
Write-Host ""
Write-Host "Looking UP result"$DomainNameItem -foreground yellow
Write-Host ""
$hostname = [System.Net.DNS]::GetHostByName($DCListItem).HostName.toupper()
$ipaddress = [System.Net.Dns]::GetHostAddresses($DomainNameItem).IPAddressToString
foreach ($ip in $ipaddress){
Write-Host ""
Write-Host "Looking UP result"$ip -foreground green
foreach ($topdns in $DCList){
$RESULTS = nslookup $ip $topdns
Write-host $RESULTS
}
}
}
}
Catch{
write-host "error"
}
Write-Host ""
Write-Host ""
pause
Got it! This will save me tonnes of work determining if a DNS cleanup is necessary. Thanks guys, I'm learning just how great Powershell can be :)
Try this:
$topDomainControllers = #("10.254.90.17", "10.225.224.17", "10.110.33.32", "10.88.100.10")
$DomainName="office.adroot.company.net"
try {
$hostname = [System.Net.Dns]::GetHostByName($topDC1).HostName.ToUpper()
$ipAddresses = [System.Net.Dns]::GetHostAddresses($DomainName) |
select -ExpandProperty IPAddressToString
foreach ($ipAddress in $ipAddresses) {
$nslookupResult = nslookup $ipAddress
$foundIp = $nslookupResult[1] -match "^\D*(\d+\.\d+\.\d+\.\d+)$"
if ($foundIp -eq $false) {
continue
}
$domainController = $Matches[1]
if ($topDomainControllers.Contains($domainController)) {
Write-Output -Verbose "Found domain controller match for $domainController"
break
} else {
Write-Output -Verbose "No match found for domain controller $domainController"
}
}
} catch {
Write-Output "An error has occured: $_"
}
I have the following PowerShell script to run a quick HitmanPro scan on computers. I have deployed this script through GFI RMM and while it works, I need to pass it domain administrator information.
$HitmanParameters = "/scanonly /quick /noinstall /quiet"
$AgentPath = (${env:ProgramFiles(x86)}, ${env:ProgramFiles} -ne $null)[0]
if (Test-Path "$AgentPath\Advanced Monitoring Agent") {
$AgentPath="$AgentPath\Advanced Monitoring Agent"
} elseif (Test-Path "$AgentPath\Advanced Monitoring Agent GP") {
$AgentPath="$AgentPath\Advanced Monitoring Agent GP"
} else {
Write-Host "Agent Path Not Found"
}
if (-not (Test-Path "$AgentPath\HitmanPro")) {
Write-Host "Creating Hitman Folder"
[system.io.directory]::CreateDirectory("$AgentPath\HitmanPro")
}
$HitmanParameters = "$HitmanParameters /log=""$AgentPath\HitmanPro\results.txt"""
if (-not (Test-Path "$AgentPath\HitmanPro\HitmanPro.exe")) {
Write-Host "HitmanPro Not found"
if ($(Get-WmiObject -Query "SELECT * FROM Win32_Processor WHERE AddressWidth='64'")) {
$HMPURL = "http://dl.surfright.nl/HitmanPro_x64.exe"
} else {
$HMPURL = "http://dl.surfright.nl/HitmanPro.exe"
}
Write-Host "Downloading $HMPURL ..."
$webClient = New-Object System.Net.WebClient
$webClient.DownloadFile($HMPURL,"$AgentPath\HitmanPro\HitmanPro.exe")
if (Test-Path "$AgentPath\HitmanPro\HitmanPro.exe") {
Write-Host "Download Complete!"
} else {
Write-Host "Error Downloading Hitman Pro"
}
}
if (Test-Path "$AgentPath\HitmanPro\HitmanPro.exe") {
Write-Host "Running HitmanPro Scan..."
Write-Host "HitmanPro.exe $HitmanParameters"
Start-Process -FilePath "$AgentPath\HitmanPro\HitmanPro.exe" -ArgumentList "$HitmanParameters" -NoNewWindow -Wait
If (Test-Path "$AgentPath\HitmanPro\results.txt") {
$data = Get-Content -Encoding Unicode "$AgentPath\HitmanPro\results.txt"
remove-item "$AgentPath\HitmanPro\results.txt"
foreach ($line in $data) {
If($line.contains("Threats")) {
$Infections = [int] $line.Split(":")[1]
If($Infections -eq 0) {
Write-Host "No Infections Found"
$data
exit 0
break
} Else {
Write-Host "Infections Found!"
$data
exit 1000
break
}
} #If Line contains Threats
} #ForEach
} Else {
Write-Host "No Logfile Found"!
} #LogFile Found
} Else {
Write-Host "HitmanPro Still Not Found!"
}#HitmanPro Found