$line.StartsWith on multiple options - powershell

I want to be able to scan for two separate values in a line how do I do this?
$file = Get-Content "D:\path\tmp\certlist.txt"
foreach ($line in $file)
{
if ($line.StartsWith("snl") or $line.StartsWith("HSM1"))
{
$baseKey = "app.swift.snl."
$profileName = $line.Substring(0,13).TrimEnd()
$certType = $line.Substring(29,10).TrimEnd()
$renewalDate = Get_Unixtime $line.Substring(42,11).TrimEnd()
$expiryDate = Get_Unixtime $line.Substring(58,11).TrimEnd()
Send_Zabbix ($baseKey + $profileName + "." + $certType + ".renewaldate") $renewalDate
Send_Zabbix ($baseKey + $profileName + "." + $certType + ".expirydate") $expiryDate
}
}
The above doesn't work. It gives me an unexpected token.

For checking if a variable starts with one of several values a regular expression might be a better approach than daisy-chained StartsWith() calls.
if ($line -cmatch '^(snl|HSM1)')
{
...
}
^ matches the beginning of a string, (snl|HSM1) matches either snl or HSM1. -cmatch does a case-sensitive match. If you don't need case-sensitivity use -imatch or just -match.

Apparently all I needed was a '-'
if ($line.StartsWith("snl") -or $line.StartsWith("HSM1"))

Related

Integer incrementing 2 times in foreach loop

I'm trying to figure out why my "$count--" is incrementing the integer down by 2 every time it cycles to a new IP. I want this to count down by 1 every time a new IP is being checked.
function scrape {
$PortList = #(443, 4433, 444, 433, 4343, 4444, 4443)
$IPList = $text1.text.split("`r")
$IPList = $text1.text.split()
$count = ($IPList.Count - 1)/2
Write-Host $IPList
Write-Host 'Firewalls with open ports will be listed here as they are discovered. Please wait while the script' `n 'processes the list of IP addresses. There are'$count 'IP addresses to check'
foreach ($IP in $IPList) {
$count--
foreach ($Port in $PortList) {
$url = "https://${IP}:${Port}"
$verb = 'GET'
$SiteData = try{httpget $url $verb}Catch{Continue}
If ($SiteData.Contains("auth1.html")) {
Write-Host ('https://' + $IP + ':' + $Port + " MGMT " + $IP) -ForegroundColor Red
$text2.text += ('https://' + $IP + ':' + $Port + " MGMT " + $IP + "`n")
}
Else {
If ($SiteData.Contains("SSLVPN")) {
Write-Host ('https://' + $IP + ':' + $Port + " SSLVPN " + $IP)
$text2.text += ('https://' + $IP + ':' + $Port + " SSLVPN " + $IP + "`n")
}
Else {
Write-Host ('https://' + $IP + ':' + $Port + " OTHER " + $IP)
$text2.text += ('https://' + $IP + ':' + $Port + " OTHER " + $IP + "`n")
}
}
}
}
}
EDIT/UPDATE: Okay so I figured out that the loop is counting blank space between the IP addresesses as a member of the array, which is causing that double decrement. Now I just have to figure out how to have it only count the addresses.
This looks suspicious:
$count = (15 - 1)/2
Have you tried running your script and outputting the value of $count from within the foreach loop to confirm that the value is what you think it is?
I also think you need to move the incremented statement AFTER doing the work.
Using the example below, the count output will return the following:
count: + 3 count: + 2 count: + 1 count: + 0
function scrape {
$PortList = #(443, 4433, 444, 433, 4343, 4444, 4443)
#$IPList = $text1.text.split("`r")
#$IPList = $text1.text.split()
$IPList = ("IP:A", "IP:B", "IP:C", "IP:D")
$count = ($IPList.Count - 1)
Write-Host $IPList
#Write-Host 'Firewalls with open ports will be listed here as they are discovered. Please wait while the script' `n 'processes the list of IP addresses. There are'$count 'IP addresses to check'
foreach ($IP in $IPList) {
Write-Host "count: " + $count
# go do some stuff
$count--
}
}
As you've since noticed, your problem is that your $IPList array contains empty elements between the IP addresses to examine.
The reason is that neither of your attempts to split a multi-line string into individual lines works correctly:
$text1.text.split("`r") # !! retains the `n after `r -> elements start with `n
$text1.text.split() # !! splits by *both* `r and `n -> empty extra elements
The simplest solution is to use the unary form of the -split operator, which conveniently splits a string into tokens by any runs of whitespace, including newlines (irrespective of whether they are Windows-style CRLF newlines (`r`n) or Unix-style LF-only newlines (`n)):
-split $text1.text # split by runs of whitespace, including newlines
Note, however, that if the individual lines contain intra-line whitespace (spaces, tabs), they will be broken into tokens as well.
If you truly only want to split by newlines (line breaks), use the binary form of the -split operator:
$text1.text -split '\r?\n' # split by CRLF or LF
Note that -split's RHS is a regular expression; \r?\n is a pattern that matches both CRLF and LF-only newlines.
If you know that the newlines are only ever the platform-appropriate ones, you can use $text1.text -split [Environment]::NewLine.

PowerShell split input and replace/combine?

I want to be able to automatically generate an output if I run a PowerShell script that splits the input by a period "." and adds "DC=" in each item/object that has been split.
$DomainFQDN = "prod.mydomain.com" # This varies depending on the input. It could be "prod.boston.us.mydomain.com" as the input.
$DistinguishedName = $DomainFQDN -split "\."
...
...
...I just don't know how to proceed
How do I get an output of "DC=prod,DC=mydomain,DC=com" for prod.mydomain.com as the input or DC=prod,DC=boston,DC=us,DC=mydomain,DC=com for prod.boston.us.mydomain.com?
Well, you can use foreach construct with $DistinguishedName and use -join like this (if you want to output directly the joined string):
$AddDC = foreach ($e in $DistinguishedName) { "DC=$e" }
Write-Host $($AddDC -join ",")
-join works like -split, you just specify the character that you need to join by.
Other way to do it is to store $AddDC
$AddDC = foreach ($e in $DistinguishedName) { "DC=$e" }
$new_string = $AddDC -join ","
Write-Host $new_string
You can consult this page for more info.
If I got it right, this is what needed:
$fqdn='prod.boston.us.mydomain.com'
$dn="DC=$($fqdn.replace('.',',DC='))"
$dn
$DomainFQDN = "prod.mydomain.com"
$DomainFQDN = $DomainFQDN.Split(".")
For ($i = 0; $i -lt $DomainFQDN.Count; $i++) {
$DomainFQDN[$i] = "DC=" + $DomainFQDN[$i]
}
$DomainFQDN = $DomainFQDN -join ","
Write-Host $DomainFQDN
Output:
DC=prod,DC=mydomain,DC=com
I'm not sure why I couldn't get the -Split "." operator to work. It should function the same as .Split(".") but for some reason it gives a different result. But anyway this should work for you.
I feel like I should mention that a real FQDN would not be DC= on every line. It would look more like:
DC=Com,DC=MyDomain,OU=Prod
I usually do a single replace operation in an expandable to convert from FQDN to distinguished name of the domain root:
$DistinguishedName = "DC=$($DomainFQDN.TrimEnd('.') -replace '\.',',DC=')"
The TrimEnd('.') call strips any dot from rooted FQDNs, and the replace operation replaces each remaining dot with ,DC=

formatting the output of a .txt in powershell

After a week of attempts I have to ask you this.
File input:
DD/MM
27,28
14,21
1
15
7
12
2,15
25
Each line of this file represents a month, so even if it´s empty, it should still count so the formatting can happen. Then based on file input, the desired output is:
Desired Output:
DD/MM
27/02
28/02
14/04
21/04
01/05
15/06
07/09
12/10
02/11
15/11
25/12
What I got so far and stuck here:
#getting the content into an array and formatting the .DAT file
$lines = Get-Content $outfileBR
If ($lines[0] -eq "DD/MM") {
$HEADER = $lines[0] + $linebreak
}
If ($lines[1] -eq '') {
continue
} Else {
$BRFILE = $lines[1].SUBSTRING(0,2) + "/01" + $linebreak
$BRFILE += $lines[1].SUBSTRING(3,2) + "/01" + $linebreak
}
If ($lines[2] -eq '') {
continue
} Else {
$BRFILE2 = $lines[2].SUBSTRING(0,2) + "/02" + $linebreak
$BRFILE2 += $lines[2].SUBSTRING(3,2) + "/02" + $linebreak
}
If ($lines[3] -eq '') {
continue
} Else {
$BRFILE3 = $lines[3].SUBSTRING(0,2) + "/03" + $linebreak
$BRFILE3 += $lines[3].SUBSTRING(3,2) + "/03" + $linebreak
}
Set-Content $BRdatFile ($HEADER + $BRFILE + $BRFILE2 + $BRFILE3)
Result:
DD/MM
/01
/01
27/02
28/02
/03
/03
Like I said, each line refers to a month, but if the line is empty (like shown in input file) I´ll not show it in the output. But on my result it´s appearing as /01 for January, /03 for march and so on.
What am I doing wrong, please?
Very similar to the answer given by Ronald Rink 'd-fens', I would do a loop within a loop, but since we know how many lines there should be in the file, I would do this:
#Get content of input file
$FileIn = Get-Content C:\Path\To\File.txt
#Start array for output with header record
[array]$FileOut += 'DD/MM'
#Loop 12 times, once for each month
ForEach($Month in (1..12)){
#Split the relevant line, and for each entry add a line to the output file
If([string]::IsNullOrEmpty($FileIn[$Month])){Continue}
$FileIn[$Month].Split(',') | ForEach{
$FileOut += '{0}/{1}' -f $_, $Month
}
}
#Output the new file
$FileOut | Set-Content C:\Path\To\NewFile.txt
Edit: I fixed 2 issues. I had [1..2] which should have been (1..12), and used the $_ reference instead of $Month (which should work anyway, but it's bad form imho).
Achieving this in PowerShell is as easy as this:
"DD/MM";
$lines = Get-Content $ENV:TEMP\input.txt;
for($c = 1; $c -lt $lines.Count; $c++)
{
$line = $lines[$c];
if(!$line) { continue; }
$line.Split(',') | % { '{0:00}/{1:00}' -f [int] $_, $c }
}
27/02
28/02
14/04
21/04
01/05
15/06
07/08
12/09
02/10
15/10
25/11
Edit: fixed $day/ $_

Is there a better way to convert all control characters to entities in PowerShell 5?

Context: Azure, Windows Server 2012, PowerShell 5
I've got the following code to convert all control characters (ascii and unicode whitespace other than \x20 itself) to their ampersand-hash equivalents.
function ConvertTo-AmpersandHash {
param ([Parameter(Mandatory)][String]$Value)
# there's got to be a better way of doing this.
$AMPERHASH = '&#'
$SEMICOLON = ';'
for ($i = 0x0; $i -lt 0x20; $i++) {
$value = $value -replace [char]$i,($AMPERHASH + $i + $SEMICOLON)
}
for ($i = 0x7f; $i -le 0xa0; $i++) {
$value = $value -replace [char]$i,($AMPERHASH + $i + $SEMICOLON)
}
return $Value
}
As can be seen by the embedded comment, I'm sure there's a better way to do this. As it stands, one does some 65 iterations for each incoming string. Would regular expressions work better/faster?
LATER
-replace '([\x00-\x1f\x7f-\xa0])',('&#' + [byte][char]$1 + ';')
looks promising but the $1 is evaluating to zero all the time, giving me  all the time.
LATER STILL
Thinking that -replace couldn't internally iterate, I came up with
$t = [char]0 + [char]1 + [char]2 + [char]3 + [char]4 + [char]5 + [char]6
$r = '([\x00-\x1f\x7f-\xa0])'
while ($t -match [regex]$r) {
$t = $t -replace [regex]$r, ('&#' + [byte][char]$1 + ';')
}
echo $t
However out of that I still get

FINALLY
function ConvertTo-AmpersandHash {
param ([Parameter(Mandatory)][String]$Value)
$AMPERHASH = '&#'
$SEMICOLON = ';'
$patt = '([\x00-\x1f\x7f-\xa0]{1})'
while ($Value -match [regex]$patt) {
$Value = $Value -replace $Matches[0], ($AMPERHASH + [byte][char]$Matches[0] + $SEMICOLON)
}
return $Value
}
That works better. Faster too. Any advances on that?
Kory Gill's answer with the library call is surely a better approach, but to address your regex question, you can't evaluate code in the replacement with the -replace operator.
To do that, you need to use the .Net regex replace method, and pass it a scriptblock to evaluate the replacement, which takes a parameter of the match. e.g.
PS C:\> [regex]::Replace([string][char]2,
'([\x00-\x20\x7f-\xa0])',
{param([string]$m) '&#' + [byte][char]$m + ';'})

Your question is a little unclear to me, and could be a duplicate of What is the best way to escape HTML-specific characters in a string (PowerShell)?.
It would be nice if you explicitly stated the exact string you have and what you want it to converted to. One has to read the code to try to guess.
I am guessing one or more of these functions will do what you want:
$a = "http://foo.org/bar?baz & also <value> conversion"
"a"
$a
$b = [uri]::EscapeDataString($a)
"b"
$b
$c = [uri]::UnescapeDataString($b)
"c"
$c
Add-Type -AssemblyName System.Web
$d = [System.Web.HttpUtility]::HtmlEncode($a)
"d"
$d
$e = [System.Web.HttpUtility]::HtmlDecode($d)
"e"
$e
Gives:
a
http://foo.org/bar?baz & also <value> conversion
b
http%3A%2F%2Ffoo.org%2Fbar%3Fbaz%20%26%20also%20%3Cvalue%3E%20conversion
c
http://foo.org/bar?baz & also <value> conversion
d
http://foo.org/bar?baz & also <value> conversion
e
http://foo.org/bar?baz & also <value> conversion
I have one small function which helps me replacing as per my requirement:
$SpecChars are all the characters that are going to be replaced with nothing
Function Convert-ToFriendlyName
{param ($Text)
# Unwanted characters (includes spaces and '-') converted to a regex:
$SpecChars = '\', ' ','\\'
$remspecchars = [string]::join('|', ($SpecChars | % {[regex]::escape($_)}))
# Convert the text given to correct naming format (Uppercase)
$name = (Get-Culture).textinfo.totitlecase(“$Text”.tolower())
# Remove unwanted characters
$name = $name -replace $remspecchars, ""
$name
}
Example: Convert-ToFriendlyName "My\Name\isRana\Dip " will result me "MyNameIsranaDip".
Hope it helps you.

Power shell using the Trim function

HI I have the following line to check variables from two different systems.
foreach ($val in $stafflist)
{
$found = 0
foreach ($user in $aduser)
if ((($val.Surname.trim() -eq $user.surname.trim()) -And ($val.'First Name'.trim() -eq $user.Givenname.trim())) -or (($val.Surname.trim() -eq $user.surname.trim()) -And ($val.'Known As'.trim() -eq $user.Givenname.trim())))
{
$found = 1
try
{
if ($user.EmployeeID -ne $null)
{
$val.'First Name' + " " + $val.'Known As' + " " + $val.surname + " EmployeedID already set as " + $user.EmployeeID | Out-File $outfile -Append
}
else
{
set-aduser -Identity $user -EmployeeID $val.'Person Number'
$val.'First Name' + " " + $val.'Known As' + " " + $val.surname + " Employeed set to " + $user.EmployeeID| Out-File $outfile -Append
}
} ## end of Try
Catch
{
$val.'First Name' +" " + $val.surname + "Can not be updated in AD" | Out-File $outfile -Append
}
}
So this checks each user in two lists ($stafflist and $aduser) against each other searching for matches, and when it finds a match it updates the employee ID in Active directory with the ID from the HR database.
The trouble is it has an or operator in it to account for the fact that in the HR database system either the "first name" or "known as name" or indeed both might be filled in and need to be checked.
I want to use the .Trim function in case some one has left in white spaces, but it throws and error if i place it against a variable and that variable end up as null, which is often the case with the "known as name" variable.
Can any one suggest the most efficient way to do this check and trim for each variable.
I could trim all the variables upfront after checking they are not null.
or test if they are null and if so pass them through different test strings to avoid errors but that all means more lines of code and slower execution of code.
If any one has a concise way to achieve this I would be grateful for the suggestion.
In the end I am just adding this to the start of the loop
if ($val.Surname -eq $null){} else {$val.Surname = $val.Surname.trim()}
if ($val.'First Name' -eq $null){} else {$val.'First Name' = $val.'First Name'.trim()}
if ($val.'Known As' -eq $null){} else {$val.'Known As' = $val.'Known As'.trim()}
So it early on checks for null values if not null trims it and stores it back to the variable.