I'm using PowerShell and running a tool to extract Lenovo hardware RAID controller info to identify the controller number for use later on in another command line (this is part of a SCCM Server Build Task Sequence). The tool outputs a lot of data and I'm trying to isolate just what I need from the output.
I've been able to isolate what I need, but I'm thinking there has to be a more efficient way so looking for optimizations. I'm still learning when it comes to working with strings.
The line output from the tool that I'm looking for looks like this:
0 0 0 252:0 17 DRIVE Onln N 557.861 GB dsbl N N dflt -
I'm trying to get the 3 characters to the left of the :0 (the 252 but on other models this could be 65 or some other 2 or 3 digit number)
My existing code is:
$ControllerInfo = cmd /c '<path>\storcli64.exe /c0 show'
$forEach ($line in $ControllerInfo) {
if ($line -like '*:0 *') {
$ControllerNum = $line.split(':')[0] # Get everything left of :
$ControllerNum = $ControllerNum.Substring($ControllerNum.Length -3) # Get last 3 chars of string
$ControllerNum = $ControllerNum.Replace(' ', '') # Remove blanks
Write-Host $ControllerNum
break #stop looping through output
}
}
The above works but I'm wondering if there's a way to combine the three lines that start with $ControllerNum = so I can have just have a single $ControllerNum = (commands) line to set the variable instead of doing it in 3 lines. Basically want to combine the Split, Substring and Replace commands into a single line.
Thanks!
Here's another option:
$ControllerNum = ([regex]'(\d{2,3}):0').Match($line).Groups[1].Value
Used on your sample 0 0 0 252:0 17 DRIVE Onln N 557.861 GB dsbl N N dflt -
the result in $ControllerNum wil be 252
If you want just the last digits before the first :, without any whitespace, you can do that with one or two regex expressions:
$line -replace '^.*\b(\d+):.*$','$1'
Regex explanation:
^ # start of string
.* # any number of any characters
\b # word boundary
( # start capture group
\d+ # 1 or more strings
) # end capture group
: # a literal colon (:)
.* # any number of any characters
$ # end of string
replacement:
$1 # Value captured in the capture group above
Related
Most of our files are named in a uniform syntax:
B0????????.????.??????.jpg
However occassionaly we see:
?????.B0????????.????.jpg
or
?????????.B0????????.jpg
I need a PowerShell script to pull the 'B0' and the next 8 digits. Traditionally we have just trimmed the string when the file names are uniform, but that is failing with these variations.
Does anyone have a bit of PS logic that can pull 'B0' and the next 8 digits from a string/filename?
Thanks!
$file = "?????.B0????????.????.jpg"
$index = ($file).IndexOf("B0")
$yourCharacters = ($file).Substring($index, 10)
$file.Replace($yourCharacters, "")
I have an .nc file I'm reading in matlab, and getting info out of the time variable.
the code looks like this
>> ncreadatt(model_list{3},'T','units')
ans =
'months since 1850-01-01'
what I want to do is get just the '1850' out of the answer.
Regular expression is a very powerful tool to parse and manipulate strings.
Matlab has regexp command:
line = 'months since 1850-01-01';
res = regexp( line, '\s(\d+)-', 'tokens', 'once');
year = str2double(res{1})
And the results is:
year =
1850
The regular expression used '\s(\d+)-' means:
\s - look for a single white space character (the space before 1850).
'(\d+)' - look for one or more digit ('\d+'), the parentheses means that all charcters matching here will be saved as a "token".
'-' - look for a single '-' after the digits.
You can play with it on ideone.
I'm returning some data like this in powershell :
1)Open;#1
2)Open;#1;#Close;#2;#pending;#6
3)Closed;#5
But I want an output like this :
1)1 Open
2)
1 Open
2 Close
6 pending
3)
5 Closed
The code:
$lookupitem = $lookupList.Items
$CMRSItems = $list.Items | where {$_['ID'] -le 5}
$CMRSItems | ForEach-Object {
$realval = $_['EventType']
Write-Host "RefNumber: " $_['RefID']
Write-Host $realval
}
Any help would be appreciated as my powershell isn't that good.
Without regular expressions, you could do something like the following:
Ignore everything up to the first ')' character
Split the string on the ';' character
foreach pair of the split string
the state is the first part (ignore potentially leading '#')
the number is the second part (ignore leading '#')
Or you could do it using the .NET System.Text.RegularExpressions.Regex class with the following regular expression:
(?:#?(?<state>[a-zA-Z]+);#(?<number>\d);?)
The Captures property on the MatchCollection returned by the Matches method would be a collection in which each item will contain two instances in the Group collection; named state and number respectively.
I have a script which uses robocopy to transfer files and write logs to a file "Logfile.txt" after that, i parse the file "LogFile.txt" further and skim the necessary data and write it to other text file called "LogFile_Parsed.Txt".My issue is over here.Initially i calculate no of lines and parse each and every line ; whats my goal is when i reach a line which matches the word skipped , if the line number is x; i will append out the lines (x-5) to (x+1) to the new log file "LogFile_Parsed.Txt". The line what i am talking about is below;
Total Copied Skipped Mismatch FAILED Extras
Dirs : 1 1 0 0 0 0
Now , whwere i am stuck is ; i only want to append these lines to parsed log fiel, when the digit below the line skipped or failed is greater than 0; i.e like following ;
Total Copied Skipped Mismatch FAILED Extras
Dirs : 1 1 1 0 1 0
How can it be done? the above 2 lines i mentioned are consistent throughout the log file.How can i know the exact position of digit under skipped or failed and read it? Please let me know your valuable suggestions.
If I understand correctly, you want to find any line with the word "Skipped" followed by a line with the number 1 in the column below "Skipped", and append those two lines and the five preceding lines to a new file?
Read LogFile.txt into an array
Iterate through the array searching for lines with "Skipped"
Whenever you find one, use a regex match to see if the next line (i.e., next element of the array) has a 1 in the corresponding position
Use an array slice to get the elements from 5 preceding to 1 following the current one, and append it to the new file
The following will work if all the matching lines are formatted as in your example:
$logfile = gc '<path>\Logfile.txt'
for ($i = 0; $i -lt $logfile.count; $i++) {
if ($logfile[$i] -match 'Skipped') {
if ($logfile[$i + 1] -match '(?<=Dirs :(\s+[0-9]+){2}\s+)1') {
$logfile[($i - 5)..($i + 1)] | Out-File -Append '<path>\Logfile_Parsed.txt'
}
}
}
If the columns can vary in number and order, you'll need to use capture groups to find the ordinal position of "Skipped" and check if there is a 1 in the corresponding position on the next line. That's a little more complicated, so I won't get into that if this is sufficient.
Below is a list of data in a single file. I'd like to run this in Powershell.
LESCAR85 07/31/10 1700678991
/ 70039536 $35.00
SQUADCT8 07/31/10 1698125739
/ 70039539 $35.00
RINGFIEL 07/29/10 11041563 /
70039639 $35.00
The 8 digit number and then the dollar amount at the end I would like convert to csv so that I can use that in an excel file. The first set of longer numbers is not always the same which changes the number of spaces between the 8 digit sequence I need and the dollar amount.
Thanks!
As long as ' / ' (slash bounded by spaces) always seperates the data you are interested in from the beginning of the string, then you can use this:
get-content yourDataFile.txt | foreach{(-split ($_ -split ' / ')[1] ) -join ','} > yourResult.csv
What the foreach loop does:
splits each line at the ' / '
Takes the second part of the split (what you are interested in), and splits again at whitespace.
The resulting elements are then joined together using a comma.