try-catch bypassing a step - function

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

Related

Trying to use remote variable in If-Condition within ScriptBlock using PowerShell

I am trying to use below code to remove the groups from Active Directory. I am maintaining an input file for the list of servers. the input file is in the local machine and trying to use the content of the file inside the ScriptBlock using ($Using:variablename) after taking a remote session.
I am getting the content[file content] of the variable inside the ScriptBlock which is defined outside the ScriptBlock. The issue is the if condition [if($serverlist -ne $null)] is satisfying even if the variable is empty. The code is entering into if block even if the variable $serverlist is null, instead it has to take else block.
Could you please help me on this.
$adserver = Read-Host -Prompt "Please enter AD server details"
$adserver
$askcredential = $host.ui.PromptForCredential("Need credentials", "Please enter your user name and password.", "", "NetBiosUserName")
$credential = New-Object System.Management.Automation.PsCredential($askcredential.UserName,$askcredential.Password)
$session = New-PSSession -ComputerName "$adserver" -Credential $credential
#$command = (Get-ADForest).domains
$addomain = Read-Host -Prompt "Please enter the Domain"
$servers = Get-Content "D:\Bhargavi\Windows-Decommission\$addomain\servers.txt"
#Invoke-Command -ComputerName $adserver -Authentication Default -Credential $credential -ScriptBlock {
Invoke-Command -Session $session -ScriptBlock {
#$addomain = Read-Host -Prompt "Please enter the Domain"
#$servers = Get-Content "D:\Bhargavi\Windows-Decommission\$addomain\servers.txt"
#Param($domainname,$serverlist)
$serverlist = $Using:servers
$domainname = $Using:addomain
Write-Host "the list is $serverlist"
Write-Host "the domain is $domainname"
if($serverlist -ne $null)
{
Write-Host "Found the data in the input file. Proceeding to remove the groups."
foreach ($server in $serverlist)
{
write-host "Server Name is: $server"
$mgserver = "MG-$server"
$mggroup = Get-ADGroup -Filter { Name -like $mgserver }
$mggroup
if($mggroup -ne $null)
{
Get-ADGroup -Filter { Name -like $mgserver } #| Remove-ADGroup -Confirm:$False
$mggroupconfirm = Get-ADGroup -Filter { Name -like $mgserver }
if($mggroupconfirm -eq $null)
{
Write-Host "$mgserver is removed from $domainname"
#Set-Content -Path "D:\Bhargavi\Windows-Decommission\$domainname\servers.txt" -Value (get-content -Path "D:\Bhargavi\Windows-Decommission\$domainname\servers.txt" | Select-String -Pattern "$server" -NotMatch)
}
else
{
Write-Host "$mgserver is not removed. Please try again."
}
}
else{Write-Host "There is no group called $mgserver in $domainname domain "}
}
}
else
{
DO
{
$val = Read-Host -Prompt "Do you want to enter servername ? Enter yes or no"
if($val -eq "yes")
{
$entermgserver = Read-Host -Prompt "Please enter the server name"
$entermgserver
$mgserver = "MG-$entermgserver"
$mgserver
$mggroup = Get-ADGroup -Filter { Name -like $mgserver }
$mggroup
if($mggroup -ne $null)
{
#Write-Host "$mggroup is not null"
Get-ADGroup -Filter { Name -like $mgserver } #| Remove-ADGroup -Confirm:$False
$mggroupconfirm = Get-ADGroup -Filter { Name -like $mgserver }
if($mggroupconfirm -eq $null)
{
Write-Host "$mgserver is removed"
}
else
{
Write-Host "$mgserver is not removed. Please try again."
}
}
else{Write-Host "The is no group called $mgserver in $domainname domain"}
}
}until ($val -eq "no")
}
} ### End Script Block
Clear-Content "D:\Bhargavi\Windows-Decommission\$addomain\servers.txt"
Remove-PSSession -Session $session

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

How to pass multiple domain and local user accounts into a function

I have a script that I have been trying to massage and I want to take a loop that was copied multiple times for each user and I want to turn it into a function.
I have figured out to pass multiple local users to the script and I have been able to pass one domain user to the script and have it work successfully.
But I want to be able to create a list of users and their domains (some have none)
and pipe that into the function automatically. I know I could just keep writing out the function with each username and password but If I can avoid that, that would be great
Function Launch-cfm {
Param (
[Parameter(Mandatory=$true, Position=0)]
[string] $username,
[Parameter(Mandatory=$false, Position=1)]
[string] $domain
)
if ($domain -eq $tue) {
Stop-Process -name "autohotkey" -Force -ErrorAction SilentlyContinue
&$OutFile
$user = "$username"
$user_sam = ($members | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}) -contains $user
if ($user_sam -eq $true) {
$user = "$username"
$account = $user
$PassFile = $CredPath+$user+,"_Password.txt"
$keyFile = $CredPath+$user+,".key"
$key = Get-content $keyFile
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $account, (Get-Content $PassFile | ConvertTo-SecureString -Key $key)
Write-Host "info to user about scripts actions."
C:
Start-Process -FilePath $mmcPath -ArgumentList $mscPath -Credential $cred;pause
} else { Write-Host "$user does not exist on this server!!!! Moving on...!
"}
} else {
Stop-Process -name "autohotkey" -Force -ErrorAction SilentlyContinue
&$OutFile
$user = "$username"
$user_sam2 = ($members | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}) -contains $user
if ($user_sam2 -eq $true) {
$account = $domain+,"\"+$user
$PassFile = $CredPath+$user+,"_Password.txt"
$keyFile = $CredPath+$user+,".key"
$key = Get-content $keyFile
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $account, (Get-Content $PassFile | ConvertTo-SecureString -Key $key)
Write-Host "info to user about scripts actions"
Start-Process -FilePath $mmcPath -ArgumentList $mscPath -Credential $cred;pause
} else { Write-Host "$user does not exist on this server!!!! Moving on...!
"}
}
}
$use = "User1","user2"
$dom = "domain1",""
launch-cfm -username $use -domain $dom
any suggestion would be great. or to know if what I am asking is even possible.
Thanks.
What I think you are looking for is a never ending parameter. Give this a try.
Input: Launch-cfm -usernames "Drew","Cleadus","Stack" -domain "SuperDomain1337"
Function Launch-cfm {
Param (
[Parameter(Mandatory=$true)]
[string[]] $usernames,
[Parameter(Mandatory=$false)]
[string] $domain
)
Foreach($user in $usernames){
Do-Magic
}
}
Reasoning:
I am not a fan of positional parameters, throw them where they feel right in the moment.
Using [string[]] instead of [string] means that it will put all values passed to it into an array for later use within the function. This current configuration allows for MULTIPLE users but only ONE domain. You can change that but would need to iterate over each domain and user at a time, unless specified within the script some how.
EG.
Foreach($dom -in $domain){
Foreach($user in $usernames){
Do-Magic
} Else {
Do-LessImpressiveMagic
}
}

How to apply colors in powershell output

Requirement :
I am beginner in powershell. Below ps script is giving the details about services are in started state or in stopped state but my requirement is I need to see this out put as background color in 'Sky Blue', if services are running then highlight in Green ,Stopped services in Red color. How do I achieve it.
Help on this is highly appriciated.
$Result = #()
foreach($server in Get-Content C:\PowerSQL\List.txt)
{
$Services=gwmi win32_service -computername $server | where {$_.Name -like ‘*SQL*’}
if(!(Test-Connection -Cn $server -BufferSize 16 -Count 1 -ea 0 -quiet))
{“Problem still exists in connecting to $server”}
ELSE {
$services | ForEach {
If ($_)
{ $Result += New-Object PSObject -Property #{
‘Host Name’ = $_.Systemname
‘Service Display Name’ = $_.Displayname
‘Service Name’ = $_.Name
‘Start Mode’ = $_.Startmode
‘Service Account Name’ = $_.Startname
‘State’ = $_.State
‘Status’= $_.Status
}
}
}
}
}
$Result | ConvertTo-HTML | Out-File C:\PowerSQL\service.htm
See my answer to similar question to this.
Communary.ConsoleExtensions [link] might help you
Invoke-ColorizedFileListing C:\Windows -m *.dmp
The above command will colorise file types and highlight dump files.
To save a color output, you would have to save to a format that preserves color, like RTF, or HTML. Txt (plain text file) only stores text.
The code below will save your output as an html file.
$time = (Get-Date).AddYears(-2)
Get-ChildItem -Recurse | Where-Object {$_.LastWriteTime -lt $time} |
Select Directory,Name,LastWriteTime |
ConvertTo-Html -Title "Services" -Body "<H2>The result of Get-ChildItem</H2> " -Property Directory,Name,LastWriteTime |
ForEach-Object {
if ($_ -like '<tr><td>*') {
$_ -replace '^(.*?)(<td>.*?</td>)<td>(.*?)</td>(.*)','$1$2<td><font color="green">$3</font></td>$4'
} else {
$_
}
} | Set-Content "$env:TEMP\ColorDirList.html" -Force
The line:
if ($_ -like '<tr><td>*') {
...checks for line in the html output that is a table row.
The line:
$_ -replace '^(.*?)(<td>.*?</td>)<td>(.*?)</td>(.*)','$1$2<td><font color="green">$3</font></td>$4'
...uses a RegEx to replace the 2nd table cell contents with a font tag with the color green. This is a very simple RegEx search & replace that will only color the 2nd column.
And here's another implementation of console only coloring, based on this link
$linestocolor = #(
'CSName Version OSArchitecture'
'------ ------- --------------'
'BENDER 6.1.7601 64-bit '
'LEELA 6.1.7601 64-bit '
'FRY 6.1.7600 64-bit '
'FARNSWORTH 6.1.7601 32-bit '
)
# http://www.bgreco.net/powershell/format-color/
function Format-Color {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true,Mandatory=$true)]
$ToColorize
, [hashtable]$Colors=#{}
, [switch]$SimpleMatch
, [switch]$FullLine
)
Process {
$lines = ($ToColorize | Out-String).Trim() -replace "`r", "" -split "`n"
foreach($line in $lines) {
$color = ''
foreach($pattern in $Colors.Keys){
if (!$SimpleMatch -and !$FullLine -and $line -match "([\s\S]*?)($pattern)([\s\S]*)") { $color = $Colors[$pattern] }
elseif (!$SimpleMatch -and $line -match $pattern) { $color = $Colors[$pattern] }
elseif ($SimpleMatch -and $line -like $pattern) { $color = $Colors[$pattern] }
}
if ($color -eq '') { Write-Host $line }
elseif ($FullLine -or $SimpleMatch) { Write-Host $line -ForegroundColor $color }
else {
Write-Host $Matches[1] -NoNewline
Write-Host $Matches[2] -NoNewline -ForegroundColor $color
Write-Host $Matches[3]
}
}
}
}
$linestocolor | Format-Color -Colors #{'6.1.7600' = 'Red'; '32-bit' = 'Green'}
# doesn't work...
# (Get-ChildItem | Format-Table -AutoSize) | Format-Color -Colors #{'sql' = 'Red'; '08/07/2016' = 'Green'}
# does work...
Format-Color -ToColorize (Get-ChildItem | Format-Table -AutoSize) -Colors #{'sql' = 'Red'; '08/07/2016' = 'Green'}
return
EDIT. to answer the OPs request
$Result = #()
foreach($server in Get-Content C:\PowerSQL\List.txt)
{
$Services=gwmi win32_service -computername $server | where {$_.Name -like ‘*SQL*’}
if(!(Test-Connection -Cn $server -BufferSize 16 -Count 1 -ea 0 -quiet))
{“Problem still exists in connecting to $server”}
else {
$services | ForEach {
If ($_)
{ $Result += New-Object PSObject -Property #{
HostName = $_.Systemname
ServiceDisplayName = $_.Displayname
ServiceName = $_.Name
StartMode = $_.Startmode
ServiceAccountName = $_.Startname
State = $_.State
Status = $_.Status
}
}
}
}
}
$Result | ConvertTo-HTML `
-Title "Services" `
-Body "<H2>The result of gwmi win32_service</H2> " `
-Property HostName,ServiceDisplayName,ServiceName,StartMode,ServiceAccountName,State,Status |
ForEach-Object {
if ($_ -like '<tr><td>*') {
switch ($_) {
{ $_ -like '*<td>Stopped</td>*' } {$color='red'}
{ $_ -like '*<td>Running</td>*' } {$color='green'}
Default {$color='white'}
}
$_.Replace('<tr>', "<tr bgcolor=`"$color`">")
} else {
$_
}
} | Set-Content C:\PowerSQL\service.htm -Force

Powershell Export to CSV with three coumns

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