Processing a list with Powershell on a Scheduled Task - powershell

I'm a newbie to powershell, so I'm not sure if I am over thinking what I want to do, hopefully somebody can help me out.
I want to create a Windows scheduled task that calls my powershell script every 4 hours, no problems there. The script needs to process a list of ID's that range from 1 to 140,(They skip a few here and there which makes this harder) the script is just calling another external program that takes about 2 hours per ID, we give it 4 hours to be safe. So upon the powershell script loading, it needs to read from a file the last scan it did, I can do that using
$lastscan = Get-Content'lastScan.txt'
Then the script needs to find the next object in the list, which may skip a number here or there so it's not as simple as just incrementing the last scan run. Once it has the next ID it will kick off the scan and save the new value to the text file named "lastScan.txt" and exit. The only thing I need help with, is how to find the next scan in my list based on the lastscan run. The list is seperated by newline, but I could edit it if it makes it easier.
1
5
6
9
etc, etc, ...

Assuming you have a string array that was populated with Get-Content and assuming the array did not contain duplicates, you could use the Array.IndexOf method to get the index of the current id and then return the next element in the array. Example:
$x = "1","2","3"
$currentId = "2"
$nextIndex = [array]::IndexOf($x, "2") + 1
$nextId = $x[$nextIndex] #nextId should now be "3"

Related

Every last itteration failing in start loop stage

I have created a genric sequence job.
Exec command >> start loop >> job activity >> end loop
Here in exec command stage i have written a script to get list of files present in directory as csv values, and the file count will varry.
file,file2,file3
But when i run the job every last itteration fails showing below error
#job_activity,error calling DSSetParam(name), code =-4
Not sure if you figured it out yet, but I was having the same problem. Per one of your comments about handling the #FM, are you doing that inside an Ereplace function (e.g., Ereplace(<string>,#FM,'')?
I had this in my StartLoop activity and after trying several different things, I fixed the issue by adding a new UserVariables activity in-between the command and loop and moving the Ereplace function to it and then using the new user variable as the list in the loop.
Assuming this works for you too, your new flow will look something like this: exec command (where you pull the list and nothing more) >> user variables (create one variable with the Ereplace(<name>.$CommandOutput,#FM,'') [replace the name with whatever you called your exec command] in the expression) >> start loop >> job activity >> end loop.
I haven't been able to find anything from IBM as to why adding that extra step works (hopefully someone else is more successful), but it's what did the trick for me.
Hope that helps.

how to extract strings in between period, asterisk and words

I have this powershell script. The idea is to generate a report but the I need to split the string on "certificate.common_name" and put on separate column.
here's my script, and this works okay, however, I cannot assume the client code will always start in position 7.
$WriteStr = $order.certificate.common_name, $order.date_created, $order.certificate.days_remaining, $order.certificate.common_name.Substring(7,2), $Tag -join, ","
so basically, I want to get "1z" on this string(certificate.common_name) "*.test.1z.sample.com"

How to take a substring with the endpoint being a carriage return and/or line feed?

How do I take a substring where I don't know the length of the thing I want, but I know that the end of it is a CR/LF?
I'm communicating with a server trying to extract some information. The start point of the substring is well defined, but the end point can be variable. In other scripting languages, I'd expect there to be a find() command, but I haven't found one in PowerShell yet. Most articles and SE questions refer to Get-Content, substring, and Select-String, with the intent to replace a CRLF rather than just find it.
The device I am communicating with has a telnet-like command structure. It starts out with it's model as a prompt. You can give it commands and it responds. I'm trying to grab the hostname from it. This is what a prompt, command, and response look like in a terminal:
TSS-752>hostname
Host Name: ThisIsMyHostname
TSS-752>
I want to extract the hostname. I came across IndexOf(), which seems to work like the find command I am looking for. ":" is a good start point, and then I want to truncate it to the next CRLF.
NOTE: I have made my code work to my satisfaction, but in the interest of not receiving anymore downvotes (3 at the time of this writing) or getting banned again, I will not post the solution, nor delete the question. Those are taboo here. Taking into account the requests for more info from the comments has only earned me downvotes, so I think I'm just stuck in the SO-Catch-22.
You could probably have found the first 20 examples in c# outlining this exact same approach, but here goes with PowerShell examples
If you want to find the index at which CR/LF occurs, use String.IndexOf():
PS C:\> " `r`n".IndexOf("`r`n")
2
Use it to calculate the length parameter argument for String.Substring():
$String = " This phrase starts at index 4 ends at some point`r`nand then there's more"
# Define the start index
$Offset = 4
# Find the index of the end marker
$CRLFIndex = $string.IndexOf("`r`n")
# Check that the end marker was actually found
if($CRLFIndex -eq -1){
throw "CRLF not found in string"
}
# Calculate length based on end marker index - start index
$Length = $CRLFIndex - $Offset
# Generate substring
$Substring = $String.Substring($Offset,$Length)

Powershell - Efficient Way to Return Line Numbers from Logs

I have an extremely large log file (max 1GB) which is appended to throughout the day. There are various strings within this log which I would like to search for (that I can already achieve using Select-String) however I am scanning the whole file on every sweep which is inefficient and a tad unnecessary.
Ideally I want to scan only the last 5 minutes of the log for these strings on each sweep. Unfortunately not every row of the log file contains a timestamp. I initially thought of doing a wildcard select-string for the last 5 mins timestamps combined with the strings of interest will miss some occurrences. My only other idea at the moment is to determine the line numbers of interest, $FromLineNumber (5 mins before current system time) and $ToLineNumber (the very last line number of log file) and then only Select-String between those two line number ranges.
As an example, to search between line 50 and the final line of the log. I am able to return the line number of $FromLineNumber but I'm struggling with grabbing $ToLineNumber for final row of log.
Q. How do I return only the line number of the final row of a log file?
So far I have tried returning this with Get-Content $path -tail -1 (object type linenumber) however this always returns blank values even with various switches and variations. I can only return line numbers via the Select-String cmdlet however I do not have a specific string to use that relates to the final row of the log. Am I misusing this cmdlet per its original design and if so...is there any other alternative to return the last line number?
Continued...Once I have determined the line number range to search between would I isolate those rows using a Get-Content loop between
$FromLineNumber and $ToLineNumber first to filter down to this smaller selection and then pipe this into a Select-String or is there a more efficient way to achieve this? I suspect that looping through thousands of lines would be demanding on resources so I'm keen to know if there is a better way.
Here is the answer to the first question
From https://blogs.technet.microsoft.com/heyscriptingguy/2011/10/09/use-a-powershell-cmdlet-to-count-files-words-and-lines/
If I want to know how many lines are contained in the file, I use the Measure->Object cmdlet with the line switch. This command is shown here:
Get-Content C:\fso\a.txt | Measure-Object –Line

Powershell: search backwards from end of file

My script reads a log file once a minute and selects (and acts upon) the lines where the timestamp begins with the previous minute.
This is easy (the regex is simply "^$timestamp"), but when the log gets big it can take a while.
My thinking is the lines I want will always be near the bottom of the file, so I'd be searching far fewer lines if I started at the bottom and searched upwards, stopping when I get to the minute prior to the one I'm interested in.
My question is, how can I search from the bottom of the file instead of the top? Can I even say "read line $length", or even "read line n" (if so I could do a sort of binary search thing to find the length of the file and work backwards from there)?
Last question: would this even be faster (I'd still like to know how to do it even if it wouldn't be faster)?
Ideally, I'd like to do this all in my own code without installing anything extra.
Thanks
get-content bigfile.txt -tail 10
This words on huge files nearly instantly without any big memory usage.
I did it with a 22 GB text file in my testing.
Doing something like "get-context bigfile.txt | select -Last 10" works but it seems to have to load all of the lines (or objects in powershell) then does the select.
May I suggest just changing the regex to equal Get-Date + whatever time period you want?
For example (and this is without your log so i apologize)
$a = Get-Date
$hr = $a.Hour
$min = $a.Minute
Then work off those values to build out the regex to select the times you want. And if you don't already use it this website is awesome for building regex's quickly and easily http://gskinner.com/RegExr/ .
Got another fix, I think you will like this..
$a = get-content .\biglog.text
Use the length to slice the array from back to front change write host to select-string and your regex or whatever you want to do in reverse..
foreach($x in $a.length..0){ write-host $a[$x] }
Another option after the get-content cmdlet again, this option just reverse orders the array then you are reading $a from bottom to top
[array]::Reverse($a)
dc
If you only want the last bit of the file, depending on the format, you can just do this:
Get-Content C:\Windows\WindowsUpdate.log | Select -last 10
This will return the last 10 lines found in the file.