Why does the String show length 1? - powershell

In the following code, I am reading value from an Excel, match it with another string and want to read the length of the variable. However it always shows the value 1...
Can somebody explain me why?
BR
$FilePath = "randompath"
$Excel = New-Object -ComObject Excel.Application
$Workbook = $Excel.Workbooks.Open($FilePath)
$Worksheet = $Workbook.Sheets.Item(1)
$zahl1 = $worksheet.Cells.Item(1, 1).Value2
$docpath | out-string
[string]$Test = $docpath
$Cut = 13
If($Test -match("LBIW")){
$postiitonLBIW=$Test.IndexOf("LBIW")
$result1=$Test.Substring($postiitonLBIW)
$result1=$Test.Split("\")
$zahl1 = $result1 -match "LBIW"
$zahl1 = $zahl1.length
write-host $zahl1

The issue is $zahl1 is set to $true or $false, which is a length of 1.
$zahl1 = $result1 -match "LBIW"
$zahl1 = $zahl1.length
If you want the matches, you have to use $matches[n]. The way you are assigning $zahl1 is the output whether a match was found or not.
The better way:
$zahl1Len = 0 #default var incase no matches
if ($result1 -match "LBIW") { # if it has a match, process
$zahl1 = $matches[1] # or whatever match index
$zahl1Len = $zahl1.length
}
This way it is assigned the first match and counts the length, if it was matched.

Related

how to read unique values from excel column using powershell

i would like to read unique email id from a column and assign to a local variable, can anyone assist in doing that
my data will be like
i would like to get unique values from the excel and assign it to a variable using power shell
the variable should hold value in following way Nalin23#bridgestone.com;raj#bridgestone.com;kishan#bridgestone.com
To read the values from an Excel column and return it as array of values, you can use this helper function:
function Import-ExcelColumn {
# returns an array of Excel Column values
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
[string]$Path,
[Parameter(Mandatory = $false, Position = 1)]
[int]$WorkSheetIndex = 1,
[Parameter(Mandatory = $false, Position = 2)]
[int]$ColumnIndex = 1
)
# constants from https://learn.microsoft.com/en-us/office/vba/api/excel.xldirection
$xlDown = -4121
$xlUp = -4162
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$workbook = $excel.Workbooks.Open($Path)
$worksheet = $workbook.Worksheets.Item($WorkSheetIndex)
# get the first and last used row indices
$firstRow = $worksheet.Cells($worksheet.UsedRange.Rows.Count, 1).End($xlUp).Row
$lastRow = $worksheet.Cells($firstRow, 1).End($xlDown).Row
# collect the values in this column in variable $result
# start at $firstRow + 1 to skip the header itself
$result = for ($row = $firstRow + 1; $row -le $lastRow; $row++) {
$worksheet.Cells.Item($row, $ColumnIndex).Value2
}
$excel.Quit()
# IMPORTANT: clean-up used Com objects
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($worksheet) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
# $result is an array. PowerShell 'unravels' arrays when returned from a function.
# to overcome this, prefix the returned array with a unary comma.
return ,$result
}
After that, in your case use it like this:
$emailAddresses = ((Import-ExcelColumn -Path 'D:\Test\Map1.xlsx' -ColumnIndex 2) | Select-Object -Unique) -join ';'
to get a string:
Nalin23#bridgestone.com;raj#bridgestone.com;kishan#bridgestone.com
Please show the code you have attempted as a reference for everyone answering the qustion.
With that said, the below code should work for a comma separate value (.csv) file:
# Get CSV object
$csv_object = Import-CSV $path_to_csv
# Find unique entries from email_id column
$unique_emails = $csv_object.email_id | Select -Unique
# Join them with ;
$delim_emails = $unqiue_emails -join ";"

How can i split up the results of this hashtable search?

I'm trying to use this to compare my AD NT hashdump with https://haveibeenpwned.com/Passwords hashes.
I'm having trouble with the results grouping multiple usernames with the same password together.
the code:
param(
[Parameter(Mandatory = $true)]
[System.IO.FileInfo] $ADNTHashes,
[Parameter(Mandatory = $true)]
[System.IO.FileInfo] $HashDictionary
)
#>
process {
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
#Declare and fill new hashtable with ADNThashes. Converts to upper case to
$htADNTHashes = #{}
Import-Csv -Delimiter ":" -Path $ADNTHashes -Header "User","Hash" | % {$htADNTHashes[$_.Hash.toUpper()] += #($_.User)}
#Create empty output object
$mrMatchedResults = #()
#Create Filestream reader
$fsHashDictionary = New-Object IO.Filestream $HashDictionary,'Open','Read','Read'
$frHashDictionary = New-Object System.IO.StreamReader($fsHashDictionary)
#Iterate through HashDictionary checking each hash against ADNTHashes
while (($lineHashDictionary = $frHashDictionary.ReadLine()) -ne $null) {
if($htADNTHashes.ContainsKey($lineHashDictionary.Split(":")[0].ToUpper())) {
$foFoundObject = [PSCustomObject]#{
User = $htADNTHashes[$lineHashDictionary.Split(":")[0].ToUpper()]
Frequency = $lineHashDictionary.Split(":")[1]
Hash = $linehashDictionary.Split(":")[0].ToUpper()
}
$mrMatchedResults += $foFoundObject
}
}
$stopwatch.Stop()
Write-Verbose "Function Match-ADHashes completed in $($stopwatch.Elapsed.TotalSeconds) Seconds"
}
end {
$mrMatchedResults
}
}
I tried commenting out | % {$htADNTHashes[$_.Hash.toUpper()] += #($_.User)} which seems to be close, but that somehow removed the Frequency column.
The results look like this:
User Frequency Hash
---- --------- ----
{TestUser2, TestUser3} 20129 H1H1H1H1H1H1H1H1H1H1H1H1H1H1H1H1
{TestUser1} 1 H2H2H2H2H2H2H2H2H2H2H2H2H2H2H2H2
I would like them separated:
User Frequency Hash
---- --------- ----
{TestUser2} 20129 H1H1H1H1H1H1H1H1H1H1H1H1H1H1H1H1
{TestUser3} 20129 H1H1H1H1H1H1H1H1H1H1H1H1H1H1H1H1
{TestUser1} 1 H2H2H2H2H2H2H2H2H2H2H2H2H2H2H2H2
i'm sure this is a simple change, but i have very little powershell experience.
The suggestion to change $FormatEnumerationLimit to -1 is not what i want either, that just fixes the list truncating.
{user1, user2, user3...}
while (($lineHashDictionary = $frHashDictionary.ReadLine()) -ne $null) {
if($htADNTHashes.ContainsKey($lineHashDictionary.Split(":")[0].ToUpper())) {
$Users = $htADNTHashes[$lineHashDictionary.Split(":")[0].ToUpper()]
foreach($User in $Users){
$foFoundObject = [PSCustomObject]#{
User = $User
Frequency = $lineHashDictionary.Split(":")[1]
Hash = $linehashDictionary.Split(":")[0].ToUpper()
}
$mrMatchedResults += $foFoundObject
}
}
}

Searching for # followed by multiple characters in word document from Powershell

I'm attempting to do a find replace on multiple word documents from Powershell. The string I'm looking to replace is in the format:
#XXXXXXX
with the X's being alphanumeric characters (this is what merge fields look like within our system).
The string I'm using as the text to find is:
"\#*"
Which I'm assuming to be anything starting with an # followed by multiple characters. The backslash acts as the escape character for the wildcard # within Word.
This is only replacing the # signs within the document though, and ignoring the characters after it.
How can I set the search term to respect the # and the characters after it and replace them all?
The full script in it's current form is:
$list = Get-ChildItem "H:\Quick Report Replace" -Include *.xml -recurse
$objWord = New-Object -ComObject word.application
$objWord.Visible = $False
foreach ($foo in $list) {
$objDoc = $objWord.Documents.Open("$foo")
$objSelection = $objDoc.Selection
$findtext= "\#*"
$ReplaceText = "_______________"
$ReplaceAll = 2
$FindContinue = 1
$MatchFuzzy = $False
$MatchCase = $False
$MatchPhrase = $false
$MatchWholeWord = $False
$MatchWildcards = $True
$MatchSoundsLike = $False
$MatchAllWordForms = $False
$Forward = $True
$Wrap = $FindContinue
$Format = $False
$objSelection.Find.execute(
$FindText,
$MatchCase,
$MatchWholeWord,
$MatchWildcards,
$MatchSoundsLike,
$MatchAllWordForms,
$Forward,
$Wrap,
$Format,
$ReplaceText,
$ReplaceAll
)
If ($objSelection.Find.Found)
{
Write-Host("The search text was found.") } Else {
Write-Host("The search text was not found.") }
$objDoc.close()
}
Word does non-greedy matches, so your expresssion \#* will only match the shortest number of characters after a literal #. Since there's nothing after the * wildcard that would act as an anchor the shortest number of characters in your case is always zero, so you'll only ever match the # character itself.
To match subsequent alphanumeric characters as well you need to anchor the end of the expression somewhere, for instance at a word boundary:
\#*>

How to count files in FTP directory

I have this script. I'm trying to count how many file are in.
clear
$ftp_uri = "ftp://ftp.domain.net:"
$user = "username"
$pass = "password"
$subfolder = "/test/out/"
$ftp_urix = $ftp_uri + $subfolder
$uri=[system.URI] $ftp_urix
$ftp=[system.net.ftpwebrequest]::Create($uri)
$ftp.Credentials=New-Object System.Net.NetworkCredential($user,$pass)
#Get a list of files in the current directory.
$ftp.Method=[system.net.WebRequestMethods+ftp]::ListDirectorydetails
$ftp.UseBinary = $true
$ftp.KeepAlive = $false
$ftp.EnableSsl = $true
$ftp.Timeout = 30000
$ftp.UsePassive=$true
try
{
$ftpresponse=$ftp.GetResponse()
$strm=$ftpresponse.GetResponseStream()
$ftpreader=New-Object System.IO.StreamReader($strm,'UTF-8')
$list=$ftpreader.ReadToEnd()
$lines=$list.Split("`n")
$lines
$lines.Count
$ftpReader.Close()
$ftpresponse.Close()
}
catch{
$_|fl * -Force
$ftpReader.Close()
$ftpresponse.Close()
}
In the directory I have three files but $lines.count return 4. $lines have 4 rows, three files and an empty line. Somebody can explain me the mystery?
The $list contains:
file1`nfile2`nfile3`n
If you split the string by "`n", you (correctly) get four parts, with the last one being empty.
You can use an overload of String.Split that takes StringSplitOptions and use RemoveEmptyEntries:
$list.Split("`n", [System.StringSplitOptions]::RemoveEmptyEntries)

Table Cycling for Powershell

I'm creating a powershell script that I want to read a value (VALUE1) from an excel table (I can convert it to XML if necessary), assign it to a variable($PLACEHOLDER), run the rest of the script, then loop back to the beginning, but instead of reading the original value(VALUE1) I want it to read the value below it(VALUE2) and overwrite $PLACEHOLDER with VALUE2, then re-run the script until it returns a blank value, then I want it to stop. I am insanely new to powershell and it's interaction with excel/xml, so any help would be greatly appreciated. (I'm self-taught, so I don't know TOO much about parameters)
Sample in Terrible Psuedo:
#Initial placeholder value here
$RowNumber = 0
#Start of the loop here, add one to previous value
$RowNumber +1
#Call the value in Column (1), Row ($RowNumber), and assign it to $RowValue
?????? = $RowValue
#Execute the command involving the data value
ECHO "C:/test/temporary/$RowValue"
#Goto the start of the loop.
If you could be so kind, would you please give a quick explanation of the functions that you use (Parameters, what's happening, ect.)
EDIT: If it could detect and skip over blank rows, that would be amazing.
EDIT3: Code for Ansgar
$xl = New-Object -COM 'Excel.Application'
$xl.Visible = $true # set to $false for production
$wb = $xl.Workbooks.Open("C:\Documents and Settings\xe474109\Desktop\EXCEL FILES\testbook2.xlsx")
$ws = $wb.Sheets.Item(1)
$row = $ws.UsedRange.Rows.Count
while ( $ws.Cells.Item($row, 1).Value -ne $null ) {
$PLACEHOLDER = $ws.Cells.Item($row, 1).Value
#
# do stuff with $PLACEHOLDER here
#(I wanted to test this by just printing the $PLACEHOLDER value
$PLACEHOLDER
$row++
}
$wb.Close()
$xl.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
Do you have Excel installed? If so, you can process Excel spreadsheets like this:
$xl = New-Object -COM 'Excel.Application'
$xl.Visible = $true # set to $false for production
$wb = $xl.Workbooks.Open('C:\path\to\your.xlsx')
$ws = $wb.Sheets.Item(1)
$row = $ws.UsedRange.Row
while ( $ws.Cells.Item($row, 1).Value -ne $null ) {
$PLACEHOLDER = $ws.Cells.Item($row, 1).Value
#
# do stuff with $PLACEHOLDER here
#
$row++
}
$wb.Close()
$xl.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
cls
$csv = Import-csv -Path 'C:\test\csvStuff.csv'
foreach ($rec in $csv) {
if ($rec.nameofyourcolumn -ne '') {
& "c:\test\temporary\$($rec.nameofyourcolumn)"
}
}