powershell highlight the blank space found - powershell

I have the following script which finds a blank space in a csv file by going line by line
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Retain blank space."
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Delete blank space."
$n = #()
$f = Get-Content C:\MyPath\*.csv
foreach($item in $f) {
if($item -like "* *"){
$res = $host.ui.PromptForChoice("Title", "want to keep the blank on this line? `n $item", [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no), 0)
switch ($res)
{
0 {$n+=$item}
1 {$n+=$item -replace ' '}
}
} else {
$n+=$item -replace ' '
}
}
$n | Set-Content C:\MyPath\*.csv
The question is: When there is a space found, how can I highlight where it is on a line or put a color there, anything that would ease the process of finding it?
EDIT: don't want to alter the file or the text, this should be done only shown in the console for PowerShell or in the window popup for ISE.

A basic code sample for the method described in the comments using Read-Host for user input and changing the background color with write-host would look like this:
$str= "test abc1 abc2 test3"
$index = $str.IndexOf(" ")
while ($index -gt -1) {
write-host $str.Substring(0,$index) -NoNewline
write-host "_" -foreground "magenta" -NoNewline
$str = $str.Substring( $index + 1, $str.length - $index - 1);
$index = $str.IndexOf(" ")
}
write-host $str.Substring( $index + 1, $str.length - $index - 1);
$confirmation = Read-Host "Do you want to keep the blank on this line?"
if ($confirmation -eq 'y') {
#do action
}
Edit: Included code for multiple white spaces
Code for initial Post:
$n = #()
$f = Get-Content C:\MyPath\*.csv
foreach($item in $f) {
if($item -like "* *"){
#$res = $host.ui.PromptForChoice("Title", "want to keep the blank on this line? `n $item", [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no), 0)
$str = $item
$index = $str.IndexOf(" ")
while ($index -gt -1) {
write-host $str.Substring(0,$index) -NoNewline
write-host "_" -foreground "magenta" -NoNewline
$str = $str.Substring( $index + 1, $str.length - $index - 1);
$index = $str.IndexOf(" ")
}
write-host $str.Substring( $index + 1, $str.length - $index - 1);
$confirmation = Read-Host "Do you want to keep the blank on this line?"
if (($confirmation -eq 'y') -or ($confirmation -eq 'Y')) {
$n+=$item
}
else {
$n+=$item -replace ' '
}
} else {
$n+=$item -replace ' '
}
}
$n | Set-Content C:\MyPath\*.csv

Related

is there a better way for me to write a script for quiz in shell

I have been at this script for 24 hours and I am getting nowhere. I am so desperate for help.
I am trying to create a quiz and I need the switches to verify if the user's input matches the 3 options; 'Y' 'N' 'G' and if true move to the next question. If not, I need the switch to then prompt the user of the default output each time the user enter's anything else besides those 3 options.
function Test-statement ($Y,$N,$G,$YY,$NN,$GG){
$check = $Y -eq $YY
$check =$check -and ($N -eq $NN)
$check =$check -and ($G -eq $GG)
$check
}
$questions = #{
"what is the current year now" = #('2023','2023','2023')
"what is the previous year" = #('2022','2022','2022')
}
foreach ($key in $questions.keys) {
$check = $false
do{
write-host ("$key" + "?")
$Y = read-host "1"
$N = read-host "2"
$G = read-host "3"
$YY = $questions.$key[0]
$NN = $questions.$key[1]
$GG = $questions.$key[2]
$check = Test-statement $Y $N $G $YY $NN $GG
if (!($check)){write-host "not true" -ForegroundColor red}
} until ($check)
}

List SPN's Script - Write results to file issue

Good morning everyone.
I found this script on the InterWeb's which works phenominal. HOWEVER... No matter what I try, and where I put it, I can't seem to get it to do the results to an out-file.
What the hell am I doing wrong, and where does the variable need to go?
# Source / credit:
# https://social.technet.microsoft.com/wiki/contents/articles/18996.active-directory-powershell-script-to-list-all-spns-used.aspx
cls
$search = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
$search.filter = "(servicePrincipalName=*)"
## You can use this to filter for OU's:
## $results = $search.Findall() | ?{ $_.path -like '*OU=whatever,DC=whatever,DC=whatever*' }
$results = $search.Findall()
foreach( $result in $results ) {
$userEntry = $result.GetDirectoryEntry()
Write-host "Object Name = " $userEntry.name -backgroundcolor "yellow" -foregroundcolor "black"
Write-host "DN = " $userEntry.distinguishedName
Write-host "Object Cat. = " $userEntry.objectCategory
Write-host "servicePrincipalNames"
$i=1
foreach( $SPN in $userEntry.servicePrincipalName ) {
Write-host "SPN ${i} =$SPN"
$i+=1
}
Write-host ""
}

Combining Powershell script to call function and get the AD attributes value

I need to use a PowerShell function to format the phone number like below:
Function Format-TelephoneNumber
{
Param (
[Parameter(ValueFromPipeline = $true, Position = 0)]
[Alias('Number')]
[string]$TelephoneNumber,
[Parameter(Position = 1)]
[string]$DefaultCountryCode = '+44'
)
Process
{
$formattedNumber = $TelephoneNumber -replace '[\x09 ]'
If ($formattedNumber -match '\A(?<CountryCode>\+[1-9]\d|0)(?<Number>\d*)\Z')
{
If ($Matches['CountryCode'] -eq '0')
{
$countryCode = $defaultCountryCode
}
Else
{
$countryCode = $Matches['CountryCode']
}
$formattedNumber = $countryCode + ' '
$formattedNumber += -join $Matches['Number'][0 .. 2] + ' '
$formattedNumber += -join $Matches['Number'][3 .. 5] + ' '
$formattedNumber += -join $Matches['Number'][6 .. 8]
$formattedNumber
}
Else
{
Write-Error "Unable to parse the string '$($number)' as telephone number!"
}
}
}
The below script is for retrieving the value of Phone Number from AD Attribute:
$sysInfo = New-Object -ComObject 'ADSystemInfo'
$userDN = $sysInfo.GetType().InvokeMember('UserName', 'GetProperty', $null, $sysInfo, $null)
$adUser = [ADSI]"LDAP://$($userDN)"
[void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($sysInfo)
Write-Host $adUser.mobile.ToString() -ForegroundColor Green
How can I call the script?
I have tried below but failed:
Write-Host "This is raw from AD: $($adUser.mobile.ToString())" -ForegroundColor Yellow
$Formatted = Format-TelephoneNumber -TelephoneNumber $adUser.mobile.ToString()
Write-Host "This is processed using Function: " "$($Formatted)" -ForegroundColor Green
Personally, I'd use a different Format-TelephoneNumber function because as James C commented, your function may truncate last digit(s) from the number.
Below is my attempt:
function Format-TelephoneNumber {
Param(
[Parameter(ValueFromPipeline = $true, Position = 0)]
[Alias('Number')]
[string]$TelephoneNumber,
[Parameter(Position = 1)]
[string]$DefaultCountryCode = '+44'
)
Process {
# replace all hyphens and other possible joining characters with space and trim the result
$number = ($TelephoneNumber -replace '[._~-]', ' ').Trim()
# test if the number starts with a country code
if ($number -match '^(\+\d+)\s') {
$countryCode = $Matches[1]
$number = $number.Substring($countryCode.Length).Trim()
}
else {
$countryCode = $DefaultCountryCode
}
# remove leading zero and any non-digits
$number = $number -replace '^0|\D', ''
if ($number.Length -lt 9) {
Write-Warning "Unable to parse the string '$($TelephoneNumber)' as telephone number!"
}
else {
$parts = #($countryCode)
# split the remaining string in to 3-character parts (+ possible remainder)
$parts += $number -split '(\d{3})' | Where-Object { $_ }
return $parts -join ' '
}
}
}
Why not use the Get-ADUser cmdlet to find the mobile property? Something like:
Import-Module ActiveDirectory
# return the mobile phone number for a user as string or nothing if not found
# $userID is either the users distinguished name, the GUID, the user SID, or the SamAccountName.
$mobile = Get-ADUser -Identity $userID -Properties MobilePhone | Select-Object -ExpandProperty MobilePhone
Note: MobilePhone is the PowerShell or GUI name for the mobile attribute, but you may use either.
Then, if you have this mobile number as string format it using the Format-TelephoneNumber function:
if ($mobile) {
Write-Host "This is raw from AD: $mobile" -ForegroundColor Yellow
$formatted = Format-TelephoneNumber -TelephoneNumber $mobile
Write-Host "This is formatted: $formatted" -ForegroundColor Green
}
Hope that answers your question

PowerShell - wrong array length/count (1 when empty) [duplicate]

This question already has answers here:
Eliminate Nulls
(2 answers)
Closed 3 years ago.
I essentially have an array $ServerList which holds a list of array I want to test, while $ExclusionList is a list of servers that have to be exluded.
The code should test the list of server with a Test-Connection and save the unreachable ones in $nonactivearray and remove them from $ServerList.
After that it will remove any entry in $ExclusionList from $ServerList.
If $ServerList becomes and empty array, it will ask the user to type the list of servers.
The code seems to work correctly until a correct server is given.
I found that, although $nonactivearray becomes empty, $nonactivearray.Count or $nonactivearray.Length return 1, hence it will enter in a endless loop since both $ServerList and $nonactivearray have number of elements greater than 0.
# Define function to center the text in the current line (taken from: https://stackoverflow.com/a/48622585/10516690)
function Write-HostCenter {
param($Message)
Write-Host ("{0}{1}" -f (' ' * (([Math]::Max(0, $Host.UI.RawUI.BufferSize.Width / 2) - [Math]::Floor($Message.Length / 2)))), $Message)
}
# Define Test-Connection as a string for Invoke-Expression later
[string]$TestConn = "Test-Connection -Quiet -Count 1 -ComputerName "
# Define excluded servers
$ExclusionList = #("Server1","Server2","Server3")
# Save old progress settings
$OldProgress = $ProgressPreference
$ProgressPreference = 'SilentlyContinue'
# Test Server availability
$nonactivearray = #() # Array of unreachable/excluded servers
$nonactive = "" # String to display the unreachable/excluded doscovered in our list of servers. Probably unnecessary, "$nonactivearray" can be used
$i = 0
foreach ($newserver in $ServerList) {
if (-Not (Invoke-Expression -Command "$TestConn $newserver")) {
$nonactive += $newserver
$nonactivearray += $newserver
if ($i -lt $ServerList.Length) {
$nonactive += " "
}
}
$i++
}
$ProgressPreference = $OldProgress
# List unreachable and excluded servers
$nonactivearray += (Compare-Object -ReferenceObject $ServerList `
-DifferenceObject $ExclusionList `
-ExcludeDifferent -IncludeEqual).InputObject
$nonactive = "$nonactivearray"
$CurPosPing = $host.UI.RawUI.CursorPosition
while ($nonactivearray.Length -ge 1) {
$host.UI.RawUI.CursorPosition = $CurPosPing
Write-Host " These HOSTS are not reachable, hence they will be ignored:"
$TempForegroundColor = $Host.Ui.RawUI.ForegroundColor # <== Temporary solution
$Host.Ui.RawUI.ForegroundColor = "Red" # <== Temporary solution
Write-HostCenter $nonactive # Write-HostCenter defined in a function. It centers the text in the shell
$Host.Ui.RawUI.ForegroundColor = $TempForegroundColor # <== Temporary solution
# Remove unreachable servers with filters
$ServerList = $ServerList | Where-Object {$nonactivearray -notcontains $_}
# Check if the new list is empty
while ($ServerList.Length -lt 1) {
Write-Host " "
$CurPos = $host.UI.RawUI.CursorPosition
Write-Host " The list of server is now empty, please type it now. " -ForegroundColor Yellow
Write-Host " Use the comma `"" -NoNewline; Write-Host "," -NoNewline -ForegroundColor Yellow
Write-Host "`" as a separator (spaces will be ignored)."
Write-Host " "
# Get list from user
# $CurPos = $host.UI.RawUI.CursorPosition
$ServerList = Read-Host -Prompt " Server list"
$ServerList = $ServerList -replace ' ',''
[string[]]$ServerList = $ServerList -split ','
$ServerList = $ServerList | Where-Object {$_.length -gt 0}
while ($ServerList.Length -lt 1) {
$Host.UI.RawUI.CursorPosition = $CurPos
Write-Host " >>> The list is STILL empty, please type it again. <<< " -ForegroundColor Yellow
Write-Host " "
Write-Host " "
# $CurPos = $host.UI.RawUI.CursorPosition
$ServerList = Read-Host -Prompt " Server list"
$ServerList = $ServerList -replace ' ', ''
[string[]]$ServerList = $ServerList -split ','
$ServerList = $ServerList | Where-Object {$_.length -gt 0}
}
}
# Re-check server connectivity
$OldProgress = $ProgressPreference
$ProgressPreference = 'SilentlyContinue'
Write-Host "serverlist"
$ServerList
$nonactivearray = #()
$nonactive = ""
$i = 0
foreach ($newserver in $ServerList) {
if (-Not (Invoke-Expression -Command "$TestConn $newserver")) {
$nonactive += $newserver
$nonactivearray += $newserver
if ($i -lt $ServerList.Length) {
$nonactive += " "
}
}
$i++
}
$ProgressPreference = $OldProgress
$nonactivearray += (Compare-Object -ReferenceObject $ServerList `
-DifferenceObject $ExclusionList `
-ExcludeDifferent -IncludeEqual).InputObject
$nonactive = "$nonactivearray"
}
Thank you and best.
[EDIT]
Sorry, I also forgot the following lines that I have added on the top of the code:
# Define function to center the text in the current line (taken from: https://stackoverflow.com/a/48622585/10516690)
function Write-HostCenter {
param($Message)
Write-Host ("{0}{1}" -f (' ' * (([Math]::Max(0, $Host.UI.RawUI.BufferSize.Width / 2) - [Math]::Floor($Message.Length / 2)))), $Message)
}
# Define Test-Connection as a string for Invoke-Expression later
[string]$TestConn = "Test-Connection -Quiet -Count 1 -ComputerName "
# Define excluded servers
$ExclusionList = #("Server1","Server2","Server3")
I hope I am not forgetting anything else...
Thank you for your help.
I could not fix the issue with the solutions proposed, but you gave me the insight to find a solution.
I searched for "how to remove $null values from an array" and I found this answer from mklement0 in another post.
I tried the following:
PS N:\> $list = #("1","","3","$null","7")
PS N:\> $list
1
3
7
PS N:\> $list -notlike ''
1
3
7
and then added the following line in my code:
$nonactivearray = $nonactivearray -notlike ''
That solved the issue. :)
Thank you again.

Using PowerShell, is it possible to overwrite a line with "Write-Host"

I have a simple file munging utility, and I would like to provide some progress feedback without creating a "scroll storm" on the console. I tried this:
param([string] $input = "", [string] $output = "")
$source = $PSBoundParameters["input"]
$destination = $PSBoundParameters["output"]
if (!$source)
{exit}
if (!$destination)
{
$destination = [System.IO.Path]::GetDirectoryName($source) `
+ "\fmt_" `
+ [System.IO.Path]::GetFileName($source)
}
$reader = [System.IO.File]::OpenText($source)
$writer = [System.IO.file]::CreateText($destination)
$lineNo = 0
try {
for(;;) {
$line = $reader.ReadLine()
if ($line -eq $null) { break }
$lineNo++
Write-Host "Processing line #:" $lineNo -NoNewline "`r"
#process the line...
$writer.Writeline($line)
}
}
finally {
$reader.Close()
$writer.Close()
}
I get output which looks like this:
Processing line #: 1 Processing line #: 2 Processing line #: 3 ...
It appears that the carriage return is not recognized or is stripped out. Is there any way to get around this with Write-Host?
If not, what would a PowerShell newbie do to overwrite the last line written to the console?
Try this:
gci *.txt |% {write-host "`r$($_.name)" -NoNewline; Start-Sleep -Seconds 1}
Modify the Write-Host line as follows:
Write-Host "`rProcessing line #: $lineNo" -NoNewline