Removing the continuous end loop for PowerShell script - powershell

I have a script for pinging IP addresses. The script is well designed so I thought of using it in my script as one of the functions. However, the problem with the script is that it has a never ending loop for pinging which I do not want. I am not able to figure out where the changes have to be made.
Function Ping-Host
{
#Parameter Definition
Param
(
[Parameter(position = 0)] $Hosts,
[Parameter] $ToCsv
)
#Funtion to make space so that formatting looks good
Function Make-Space($l,$Maximum)
{
$space =""
$s = [int]($Maximum - $l) + 1
1..$s | %{$space+=" "}
return [String]$space
}
#Array Variable to store length of all hostnames
$LengthArray = #()
$Hosts | %{$LengthArray += $_.length}
#Find Maximum length of hostname to adjust column witdth accordingly
$Maximum = ($LengthArray | Measure-object -Maximum).maximum
$Count = $hosts.Count
#Initializing Array objects
$Success = New-Object int[] $Count
$Failure = New-Object int[] $Count
$Total = New-Object int[] $Count
cls
#Running a never ending loop
while($true){
$i = 0 #Index number of the host stored in the array
$out = "| HOST$(Make-Space 4 $Maximum)| STATUS | SUCCESS | FAILURE | ATTEMPTS |"
$Firstline=""
1..$out.length|%{$firstline+="_"}
#output the Header Row on the screen
Write-Host $Firstline
Write-host $out -ForegroundColor White -BackgroundColor Black
$Hosts|%{
$total[$i]++
If(Test-Connection $_ -Count 1 -Quiet -ErrorAction SilentlyContinue)
{
$success[$i]+=1
#Percent calclated on basis of number of attempts made
$SuccessPercent = $("{0:N2}" -f (($success[$i]/$total[$i])*100))
$FailurePercent = $("{0:N2}" -f (($Failure[$i]/$total[$i])*100))
#Print status UP in GREEN if above condition is met
Write-Host "| $_$(Make-Space $_.Length $Maximum)| UP$(Make-Space 2 4) | $SuccessPercent`%$(Make-Space ([string]$SuccessPercent).length 6) | $FailurePercent`%$(Make-Space ([string]$FailurePercent).length 6) | $($Total[$i])$(Make-Space ([string]$Total[$i]).length 9)|" -BackgroundColor Green
}
else
{
$Failure[$i]+=1
#Percent calclated on basis of number of attempts made
$SuccessPercent = $("{0:N2}" -f (($success[$i]/$total[$i])*100))
$FailurePercent = $("{0:N2}" -f (($Failure[$i]/$total[$i])*100))
#Print status DOWN in RED if above condition is met
Write-Host "| $_$(Make-Space $_.Length $Maximum)| DOWN$(Make-Space 4 4) | $SuccessPercent`%$(Make-Space ([string]$SuccessPercent).length 6) | $FailurePercent`%$(Make-Space ([string]$FailurePercent).length 6) | $($Total[$i])$(Make-Space ([string]$Total[$i]).length 9)|" -BackgroundColor Red
}
$i++
}
#Pause the loop for few seconds so that output
#stays on screen for a while and doesn't refreshes
Start-Sleep -Seconds 1
cls
}
}
Ping-Host -Hosts 10.50.5.16,10.50.5.33

Remove the while ($true) { and corresponding }. Then each time you call Ping-Host, the function will ping only once.

With help of Paul and some searching in google, came up with an solution.
Changes made
1) as paul indicated remove while($true){} loop
2) adding do while
Function Ping-Host
{
#Parameter Definition
Param
(
[Parameter(position = 0)] $Hosts,
[Parameter] $ToCsv
)
#Funtion to make space so that formatting looks good
Function Make-Space($l,$Maximum)
{
$space =""
$s = [int]($Maximum - $l) + 1
1..$s | %{$space+=" "}
return [String]$space
}
#Array Variable to store length of all hostnames
$LengthArray = #()
$Hosts | %{$LengthArray += $_.length}
#Find Maximum length of hostname to adjust column witdth accordingly
$Maximum = ($LengthArray | Measure-object -Maximum).maximum
$Count = $hosts.Count
#Initializing Array objects
$Success = New-Object int[] $Count
$Failure = New-Object int[] $Count
$Total = New-Object int[] $Count
cls
#Running a never ending loop
DO
{$j++
$i = 0 #Index number of the host stored in the array
$out = "| HOST$(Make-Space 4 $Maximum)| STATUS | SUCCESS | FAILURE | ATTEMPTS |"
$Firstline=""
1..$out.length|%{$firstline+="_"}
#output the Header Row on the screen
Write-Host $Firstline
Write-host $out -ForegroundColor White -BackgroundColor Black
$Hosts|%{
$total[$i]++
If(Test-Connection $_ -Count 1 -Quiet -ErrorAction SilentlyContinue)
{
$success[$i]+=1
#Percent calclated on basis of number of attempts made
$SuccessPercent = $("{0:N2}" -f (($success[$i]/$total[$i])*100))
$FailurePercent = $("{0:N2}" -f (($Failure[$i]/$total[$i])*100))
#Print status UP in GREEN if above condition is met
Write-Host "| $_$(Make-Space $_.Length $Maximum)| UP$(Make-Space 2 4) | $SuccessPercent`%$(Make-Space ([string]$SuccessPercent).length 6) | $FailurePercent`%$(Make-Space ([string]$FailurePercent).length 6) | $($Total[$i])$(Make-Space ([string]$Total[$i]).length 9)|" -BackgroundColor Green
}
else
{
$Failure[$i]+=1
#Percent calclated on basis of number of attempts made
$SuccessPercent = $("{0:N2}" -f (($success[$i]/$total[$i])*100))
$FailurePercent = $("{0:N2}" -f (($Failure[$i]/$total[$i])*100))
#Print status DOWN in RED if above condition is met
Write-Host "| $_$(Make-Space $_.Length $Maximum)| DOWN$(Make-Space 4 4) | $SuccessPercent`%$(Make-Space ([string]$SuccessPercent).length 6) | $FailurePercent`%$(Make-Space ([string]$FailurePercent).length 6) | $($Total[$i])$(Make-Space ([string]$Total[$i]).length 9)|" -BackgroundColor Red
}
$i++
}
#Pause the loop for few seconds so that output
#stays on screen for a while and doesn't refreshes
Start-Sleep -Seconds 1
cls
}while($j -ne 10 )
}
Ping-Host -Hosts 10.50.5.16,10.50.5.33
This will ping 10 times

Related

Problem assign data from a file read to variables

This is a PowerShell question, sorry if it wound up in the wrong place.
I have a data file which I will call PS_Upgrade_Data. It has 6 items in it listed like this:
item1=item-2=item.3=item 4=item5=item6
Please note that items 2 through 4 are written that way due to the data coming in over which I have no control. There is a dash in item2, a period in intem3 and a space in item4 just to be clear. Items 1, 5, and 6 have nothing between the word item and the number.
I am using the follow PS line to read the data in from the file:
Get-Content "P:\PS_Upgrade_Data.txt" | Where-Object {$_.length -gt 0} | Where-Object {!$_.StartsWith("#")} | Foreach-Object -begin {$count1=0} -process {$var = $_.Split('=',6).Trim()}
This does read the data from the file in ok.
I want to take that data and drop it into six (6) different variables and I tried a foreach loop like the one below:
$count1 = 0
ForEach ($item in $var) {
Write-Host "`n"
Write-Host "count = " , $count1
if($count1 = 0) {
Write-Host "UserInit"
$UserInit = $item
}
elseif ($count1 = 1) {
Write-Host "UserInit"
$TicketNumber = $item
}
elseif ($count1 = 2) {
Write-Host "UserInit"
$UpgradeVersion = $item
}
elseif ($count1 = 3) {
Write-Host "UserInit"
$ClientName = $item
}
elseif ($count1 = 4) {
Write-Host "UserInit"
$InstName = $item
}
elseif ($count1 = 5) {
Write-Host "UserInit"
$Coffee = $item
}
$count1 +=1
}
The problem is that the counter is jumping from 0 (zero) to two (2) and then wont increase and I have no idea why.
What stupid thing am I doing or missing?
Thanks for any help.
PowerShell's assignment operator = supports multiple assignment targets per operation, so you can skip the counter and foreach loop and instead, simply do:
Get-Content "P:\PS_Upgrade_Data.txt" | Where-Object {$_.length -gt 0} | Where-Object {!$_.StartsWith("#")} | Foreach-Object {
$UserInit,$TicketNumber,$UpgradeVersion,$ClientName,$InstName,$Coffee = $_.Split('=',6).Trim()
# do with your variables what you want here
}

Iterating multiple Outlook COM Object fails

We're having a very strange problem. When iterating through multiple elements in an array of public folder names, PowerShell sometimes throws an error. But not always.
When running the code below with as input only one element it works fine but when multiple elements are defined the second iteration throws an error.
According to this Microsoft article one should Release the COM-Object, but this doesn't work either.
Code
Param (
[String]$Mail = 'User#donain.com',
[String]$ImportFile = 'C:\Scripts\Import.txt'
)
$Import = Get-Content $ImportFile
$Start = "\\Public Folders - $Mail"
Add-Type -AssemblyName 'Microsoft.Office.Interop.Outlook'
foreach ($L in $Import) {
$PSTFile = "$ExportFolder\$($L -replace '[^A-Za-z0-9-_ \.\[\]]', ' ').pst"
$Outlook = New-Object -ComObject Outlook.Application -Verbose:$false
$Namespace = $Outlook.GetNameSpace('MAPI')
$AllPublicFolders = $Namespace.Folders | where FolderPath -EQ $Start | ForEach-Object {
$Start = $Start + '\All Public Folders'
$_.Folders | where FolderPath -EQ $Start
}
$Split = $L.Split('\')
$Folder = Switch ($Split.Count) {
1 {$AllPublicFolders.Folders.Item($Split[0])}
2 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1])}
3 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2])}
4 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3])}
5 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3]).Folders.Item($Split[4])}
6 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3]).Folders.Item($Split[4]).Folders.Item($Split[5])}
7 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3]).Folders.Item($Split[4]).Folders.Item($Split[5]).Folders.Item($Split[6])}
8 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3]).Folders.Item($Split[4]).Folders.Item($Split[5]).Folders.Item($Split[6]).Folders.Item($Split[7])}
9 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3]).Folders.Item($Split[4]).Folders.Item($Split[5]).Folders.Item($Split[6]).Folders.Item($Split[7]).Folders.Item($Split[8])}
}
Write-Verbose "Folder '$($Folder.FolderPath.TrimStart($Start))'"
Write-Verbose "Add PST"
$NameSpace.AddStore($PSTFile)
$PSTStore = $NameSpace.Stores | where {$_.FilePath -eq $PSTFile}
Write-Verbose "Copy content to PST"
$Folder.CopyTo($PSTStore) | Out-Null
Write-Verbose "Remove PST"
$PST = $NameSpace.Stores | where {$_.FilePath -eq $PSTFile}
$PSTRoot= $PST.GetRootFolder()
$PSTFolder= $NameSpace.Folders.Item($PSTRoot.Name)
$NameSpace.GetType().InvokeMember('RemoveStore',[System.Reflection.BindingFlags]::InvokeMethod,$null,$Namespace,($PSTFolder))
$Outlook.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Outlook)
Remove-Variable Outlook
Start-Sleep -Seconds 5
}
ImportFile
WEUR - COMPANY\DAF\Tableau de bord IB\Année 2002\07 juillet
WEUR - COMPANY\DAF\Tableau de bord IB\Année 2002\08 Août
Error
Failed for path 'WEUR - DOMAIM\DAF\Tableau de bord IB\Année 2002\08 Août': You cannot call a method on a null-va
lued expression.
Found the problem:
$AllPublicFolders = $Namespace.Folders | where FolderPath -EQ "\\Public Folders - $Mail" | ForEach-Object {
$_.Folders | where FolderPath -EQ "\\Public Folders - $Mail\All Public Folders"
}

Displaying the output into html

I got a code for pinging the servers repeatedly. That best suits for my object. But the thing I want to display the result of the code to the HTML page. How can I do it?
Function Ping-Host {
#Parameter Definition
Param (
[Parameter(position = 0)] $Hosts,
[Parameter] $ToCsv
)
#Funtion to make space so that formatting looks good
Function Make-Space($l,$Maximum) {
$space =""
$s = [int]($Maximum - $l) + 1
1..$s | %{$space+=" "}
return [String]$space
}
#Array Variable to store length of all hostnames
$LengthArray = #()
$Hosts | %{$LengthArray += $_.length}
#Find Maximum length of hostname to adjust column witdth accordingly
$Maximum = ($LengthArray | Measure-object -Maximum).maximum
$Count = $hosts.Count
#Initializing Array objects
$Success = New-Object int[] $Count
$Failure = New-Object int[] $Count
$Total = New-Object int[] $Count
cls
#Running a never ending loop
while ($true) {
$i = 0 #Index number of the host stored in the array
$out = "| HOST$(Make-Space 4 $Maximum)| STATUS | SUCCESS | FAILURE | ATTEMPTS |"
$Firstline=""
1..$out.length | %{$firstline+="_"}
#output the Header Row on the screen
Write-Host $Firstline
Write-host $out -ForegroundColor White -BackgroundColor Black
$Hosts | %{
$total[$i]++
if (Test-Connection $_ -Count 1 -Quiet -ErrorAction SilentlyContinue) {
$success[$i]+=1
#Percent calclated on basis of number of attempts made
$SuccessPercent = $("{0:N2}" -f (($success[$i]/$total[$i])*100))
$FailurePercent = $("{0:N2}" -f (($Failure[$i]/$total[$i])*100))
#Print status UP in GREEN if above condition is met
Write-Host "| $_$(Make-Space $_.Length $Maximum)| UP$(Make-Space 2 4) | $SuccessPercent`%$(Make-Space ([string]$SuccessPercent).length 6) | $FailurePercent`%$(Make-Space ([string]$FailurePercent).length 6) | $($Total[$i])$(Make-Space ([string]$Total[$i]).length 9)|" -BackgroundColor Green
} else {
$Failure[$i]+=1
#Percent calclated on basis of number of attempts made
$SuccessPercent = $("{0:N2}" -f (($success[$i]/$total[$i])*100))
$FailurePercent = $("{0:N2}" -f (($Failure[$i]/$total[$i])*100))
#Print status DOWN in RED if above condition is met
Write-Host "| $_$(Make-Space $_.Length $Maximum)| DOWN$(Make-Space 4 4) | $SuccessPercent`%$(Make-Space ([string]$SuccessPercent).length 6) | $FailurePercent`%$(Make-Space ([string]$FailurePercent).length 6) | $($Total[$i])$(Make-Space ([string]$Total[$i]).length 9)|" -BackgroundColor Red
}
$i++
}
#Pause the loop for few seconds so that output
#stays on screen for a while and doesn't refreshes
Start-Sleep -Seconds 10
cls
}
}
Ping-Host '10.50.5.33'
ConvertTo-HTML is the simple answer here but first you need to have object based output. Currently you are just outputting text to the console with Write-Host. In order to make that work you are doing some fancy formatting footwork which unfortunately is useless if you are just going to be outputting to HTML.
You can change this if you want but I didnt like the idea of while($true) since it will break the natural creation of the HTML Table. Obviously you are entitled to do what you want but this should be a working version that almost duplicates what you have. If you want to do some formatting I recommend you look up html styles.
Function Ping-Hosts{
param(
[string[]]$hosts,
[int]$MaxPings=100
)
# Hashtable that will record ongoing statistics
$results = $hosts | ForEach-Object{
#{
$_ = #{
Successes = 0
Attempts = 0
}
}
}
1..$MaxPings | ForEach-Object{
# Ping each computer a maximumn number of times.
$pingCount = $_
$hosts | ForEach-Object{
# Clear output statistics
$props = #{
Host = $_
Status = "Down" # Assume it's down.
}
# Perform a single ping
if (Test-Connection $_ -Count 1 -Quiet -ErrorAction SilentlyContinue){
# Success
$results.$_.Successes = $results.$_.Successes + 1
$props.Status = "UP"
}
# Raise the number of attempts
$results.$_.Attempts = $results.$_.Attempts + 1
# Calculate statistics
If($results.$_.Successes -eq 0){
$props.Success = "{0:p2}" -f 0
} else {
$props.Success = "{0:p2}" -f ($results.$_.Attempts / $results.$_.Successes)
}
If($results.$_.Attempts - $results.$_.Successes -eq 0){
$props.Failure = "{0:p2}" -f 0
} else {
$props.Failure = "{0:p2}" -f ($results.$_.Attempts / ($results.$_.Attempts - $results.$_.Successes))
}
$props.Attempts = $results.$_.Attempts
# Output results.
New-Object -TypeName psobject -Property $props
}
}
}
Sample execution
Ping-Hosts "c4222","C4280" | ConvertTo-Html -Fragment
Partial Sample Output
<tr><th>Host</th><th>Status</th><th>Attempts</th><th>Failure</th><th>Success</th></tr>
<tr><td>c4222</td><td>UP</td><td>1</td><td>0.00 %</td><td>100.00 %</td></tr>
<tr><td>C4280</td><td>UP</td><td>1</td><td>0.00 %</td><td>100.00 %</td></tr>
<tr><td>c4222</td><td>UP</td><td>2</td><td>0.00 %</td><td>100.00 %</td></tr>
<tr><td>C4280</td><td>UP</td><td>2</td><td>0.00 %</td><td>100.00 %</td></tr>
Closer to what you wanted
If you want something other than this I would look into css formatting closer. This is not the way I would have done it but have a look. You are complicating things by asking for the extra headers as you go (maybe there is a better way but we are off topic enough for this question)
Function Ping-Hosts{
param(
[string[]]$hosts,
[int]$MaxPings=100
)
# Hashtable that will record ongoing statistics
$results = $hosts | ForEach-Object{
#{
$_ = #{
Successes = 0
Attempts = 0
}
}
}
1..$MaxPings | ForEach-Object{
# Ping each computer a maximumn number of times.
$pingCount = $_
$hosts | ForEach-Object{
# Clear output statistics
$props = #{
Host = $_
Status = "Down" # Assume it's down.
}
# Perform a single ping
if (Test-Connection $_ -Count 1 -Quiet -ErrorAction SilentlyContinue){
# Success
$results.$_.Successes = $results.$_.Successes + 1
$props.Status = "UP"
# Set the backround color
$colour = "#2FFF18"
} else {
# Set the backround color
$colour = "#FF2020"
}
# Raise the number of attempts
$results.$_.Attempts = $results.$_.Attempts + 1
$props.Attempts = $results.$_.Attempts
# Calculate statistics
If($results.$_.Successes -eq 0){
$props.Success = "{0:p2}" -f 0
} else {
$props.Success = "{0:p2}" -f ($results.$_.Attempts / $results.$_.Successes)
}
If($results.$_.Attempts - $results.$_.Successes -eq 0){
$props.Failure = "{0:p2}" -f 0
} else {
$props.Failure = "{0:p2}" -f ($results.$_.Attempts / ($results.$_.Attempts - $results.$_.Successes))
}
# Output results.
$frag = New-Object -TypeName psobject -Property $props | ConvertTo-Html -Fragment
$frag -replace "<tr><td>","<tr bgcolor=$colour><td>"
}
}
}
Sample Call
Ping-Hosts "c4222","3" -MaxPings 2 | Set-Content c:\temp\test.html
Sample Output

How expressive can I get with a PowerShell Expression in Format-Table?

I have the following script that outputs a color coded folder hierarchy of a user's Exchange mailbox. It output the line in red if it's over a certain threshold (20 MB in this case) and gray if not.
#Get Folder Size Breakdown to Table with Color Coding
get-mailbox $username |
Get-MailboxFolderStatistics |
ft #{
Name="Name"
Expression=
{
$prefix=""
foreach($c in $_.FolderPath.ToCharArray())
{
if($c -eq '/'){$prefix+='-'}
}
if($_.FolderSize -gt 20MB)
{
$Host.UI.RawUI.ForegroundColor = "Red"
} else
{
$Host.UI.RawUI.ForegroundColor = "Gray"
}
$prefix + $_.Name
}
},
FolderSize,
FolderandSubfolderSize
There are a few problems with this script.
If the last folder processed is larger than 20 MB, my console text remains Red after it runs.
This script assumes that the original console text was Gray. If it's not Gray, then I've changed the user's console text.
Both of these are very easy to resolve if you're not in the context of a format-table expression, but I can't for the life of me figure out if it's possible to resolve these issues in this particular case. Here's the gist of what I've tried but it doesn't work. (In reality I've tried about 20 different variations).
get-mailbox $username |
Get-MailboxFolderStatistics |
ft #{
Name="Name"
Expression=
{
$prefix=""
$originalColor = $Host.UI.RawUI.ForegroundColor
foreach($c in $_.FolderPath.ToCharArray())
{
if($c -eq '/'){$prefix+='-'}
}
if($_.FolderSize -gt 20MB)
{
$Host.UI.RawUI.ForegroundColor = "Red"
}
$prefix + $_.Name
$Host.UI.RawUI.ForegroundColor = $originalColor
}
},
FolderSize,
FolderandSubfolderSize
Note: The purpose of this is to eventually compress this down to a one-liner. I know that I can store the variable before I start the pipeline and the restore the color after the pipeline is finished, but that takes the fun/aggravation out of it. I'm more curious as to whether or not I can accomplish this without altering the basic structure of this pipeline.
I don't think this is possible. Essentially, every time Format-Table reads the Expression for Name the foreground color will change. But Format-Table probably doesn't write out the value from that expression immediately, so you can't reset the color in the expression.
I think you're going to have to wrap your pipeline:
$originalColor = $Host.UI.RawUI.ForegroundColor
get-mailbox $username |
Get-MailboxFolderStatistics |
ft #{
Name="Name"
Expression=
{
$prefix = " " * (($_.FolderPath -split '/').Length)
$Host.UI.RawUI.ForegroundColor = if($_.FolderSize -gt 20MB) { "Red" } else { $originalColor }
$prefix + $_.Name
}
},
FolderSize,
FolderandSubfolderSize
$Host.UI.RawUI.ForegroundColor = $originalColor
Another option would be to write your own formatting code that finds the maximum size of each column then uses Write-Host to write things out:
$stats = get-mailbox $username |
Get-MailboxFolderStatistics |
$nameMaxWidth = 0
$sizeMaxWidth = 0
$subFolderSizeMaxWidth = 0
$stats | ForEach-Object {
if( $_.Name.Length -gt $nameMaxWidth )
{
$nameMaxWidth = $_.Name.Length + (($_.FolderPath -split '/').Length - 1)
}
$sizeWidth = $_.FolderSize.ToString().Length
if( $sizeWidth -gt $sizeMaxWidth )
{
$sizeMaxWidth = $sizeWidth
}
$subSizeWidth = $_.FolderAndSubFolderSize.ToString().Length
if( $subSizeWidth -gt $subFolderSizeMaxWidth )
{
$subFolderSizeMaxWidth = $subSizeWidth
}
}
$stats | ForEach-Object {
$colorParam = #{ }
if( $_.FolderSize -gt 20MB )
{
$colorParam.ForegroundColor = 'Red'
}
$prefix = ' ' * (($_.FolderPath -split '/').Length - 1)
Write-Host ("{0}{1,$nameMaxWidth}" -f $prefix,$_.Name) -NoNewLine #colorParam
Write-Host " " -NoNewline
Write-Host ("{0,-$sizeMaxWidth}" -f $_.FolderSize) -NoNewLine
Write-Host " " -NoNewLine
Write-Host ("{0,-$subFolderSizeMaxWidth}" -f $_.FolderAndSubFolderSize)
}

Powershell colored directory listing is incorrect with format-wide

I got this colored dir script from http://tasteofpowershell.blogspot.com/2009/02/get-childitem-dir-results-color-coded.html:
function ls {
$regex_opts = ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase -bor [System.Text.RegularExpressions.RegexOptions]::Compiled)
$fore = $Host.UI.RawUI.ForegroundColor
$compressed = New-Object System.Text.RegularExpressions.Regex('\.(zip|tar|gz|rar)$', $regex_opts)
$executable = New-Object System.Text.RegularExpressions.Regex('\.(exe|bat|cmd|ps1|psm1|vbs|rb|reg|dll|o|lib)$', $regex_opts)
$executable = New-Object System.Text.RegularExpressions.Regex('\.(exe|bat|cmd|ps1|psm1|vbs|rb|reg|dll|o|lib)$', $regex_opts)
$source = New-Object System.Text.RegularExpressions.Regex('\.(py|pl|cs|rb|h|cpp)$', $regex_opts)
$text = New-Object System.Text.RegularExpressions.Regex('\.(txt|cfg|conf|ini|csv|log|xml)$', $regex_opts)
Invoke-Expression ("Get-ChildItem $args") |
%{
if ($_.GetType().Name -eq 'DirectoryInfo') {
$Host.UI.RawUI.ForegroundColor = 'DarkCyan'
$_
$Host.UI.RawUI.ForegroundColor = $fore
} elseif ($compressed.IsMatch($_.Name)) {
$Host.UI.RawUI.ForegroundColor = 'Yellow'
$_
$Host.UI.RawUI.ForegroundColor = $fore
} elseif ($executable.IsMatch($_.Name)) {
$Host.UI.RawUI.ForegroundColor = 'Red'
$_
$Host.UI.RawUI.ForegroundColor = $fore
} elseif ($text.IsMatch($_.Name)) {
$Host.UI.RawUI.ForegroundColor = 'Green'
$_
$Host.UI.RawUI.ForegroundColor = $fore
} elseif ($source.IsMatch($_.Name)) {
$Host.UI.RawUI.ForegroundColor = 'Cyan'
$_
$Host.UI.RawUI.ForegroundColor = $fore
} else {
$_
}
}
}
It works great, but I most of the time I want only the file names, in wide format. So after the invoke-expression call, I added
Invoke-Expression ("Get-ChildItem $args") |
%{
if ($_.GetType().Name -eq 'DirectoryInfo') {
:
:
:
$_
}
} | format-wide -property Name
}
Now I have a bug. Only the colour of the second column is correct; the first item in each column takes the colour of the item in the second column. For example, if I have
> ls
Directory Program.exe
Then both Directory and Program.exe will be red, even though Directory is supposed to be DarkCyan. How can I correct this?
Rather than twiddling the foreground/background colors of the host in between displaying text to the screen, why don't you use Write-Host which gives you a bit more control over the displayed text (you can control when newlines are output) e.g.:
$_ | Out-String -stream | Write-Host -Fore Red
And for the wide listing use, you will need to handle the column formatting yourself unless you want to update the format data XML for the DirectoryInfo/FileInfo types. If you don't want to do that, then you can write out each name - padded out appropriately - with the desired color. On the last column, set the -NoNewLine param to $false:
$width = $host.UI.RawUI.WindowSize.Width
$cols = 3
ls | % {$i=0; $pad = [int]($width/$cols) - 1} `
{$nnl = ++$i % $cols -ne 0; `
Write-Host ("{0,-$pad}" -f $_) -Fore Green -NoNewLine:$nnl}
Just thought I would point you to this question I posted which outputs linux style colored output and format in columns correctly. How to write a list sorted lexicographically in a grid listed by column?