Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Hughmoris
Apr 21, 2007
Let's go to the abyss!
In PowerShell, how do I loop through a text file and insert "Sleep(500)" in between each line?

I have text files that contain AutoIt Recorder code, and I want to pause .5 seconds between each block of code. I know I could learn to do it with AutoIt but I'm curious as to what it would look like in PowerShell.

Ithaqua posted:

Let's say you're in C:\Foo\Bar\Baz\

. = C:\Foo\Bar\Baz\
.\.. = C:\Foo\Bar\
.\..\.. = C:\Foo\
etc

"." is the current directory, not "up" anything.

I definitely didn't know that. Thank you.

Hughmoris fucked around with this message at 18:43 on Jul 25, 2014

Adbot
ADBOT LOVES YOU

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Ithaqua posted:

get-content .\test.txt | % { $_ + [System.Environment]::NewLine +"Sleep(500)" } | set-content .\output.txt

Thank you for this.

Coming from kicking Python around, that all looks very confusing. But I'm getting its like any language, once you get exposed to it a little bit it all makes sense

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Ithaqua posted:

I'll break it down:

code:
get-content .\test.txt 
This opens up test.txt and reads the contents in, no surprises there.

code:
| % 
The pipe character "|" takes the results of the previous command and passes it along to the next command. "%" is short-hand for "foreach". So for each line that we pulled out of test.txt, we're going to do something to it.

code:
{ $_ + [System.Environment]::NewLine +"Sleep(500)" } 
This is the block of logic we're executing on each line. "$_" is basically "the item in our current iteration of the foreach".

So for every line ($_), we're appending [System.Environment]::NewLine (a .NET thing that just maps to \r\n or \n, depending on OS), then appending the "Sleep(500)" text to that.

code:
| set-content .\output.txt
Then when we're done, pipe all of that transformed junk into a new file called output.txt.

Thanks for breaking everything down. I've been flipping through the book and I'm thinking my needs will be better suited by AutoIt. I won't be doing much administration tasks but rather testing and the sorts that involve recording mouse movements and keystrokes. I'll definitely keep the book on the shelf though.

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Ithaqua posted:

Automated testing? Use an actual testing framework. Coded UI records your actions, translates them to .NET code, and lets you play them back. Then you can integrate it into a build/deploy process, especially if you use MTM for managing test cases.

I'm diving headfirst into this new job and am probably not explaining myself correctly. I work in informatics at a hospital and I'm testing software that our nurses use to chart on patients. The software is made by McKesson.

For my testing, I essentially open up a form, click/check/radio multiple options (sometimes random), then click SUBMIT. Afterwards I read over it and see if there are any weird errors or issues. AutoIt makes it very simple to record my mouse movement and clicks but it definitely isn't great because each form is different and each selection box may be in a different spot. Is that something I could attack with a different solution?

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Ithaqua posted:

I don't understand why you'd be testing a vendor's software. That's the vendor's job. If their poo poo doesn't work right, tell them.

That said, give Coded UI a shot if you have access to a Visual Studio SKU that supports it. It might be able to read the IDs of all of the controls, although it's a crapshoot.

We have the ability to build and customize forms based on the framework that the software creator provided us. After creating or customizing a form, we test it in a train environment before sending it out to Live. This is my first job in this capacity so I'm not sure if its the norm or not, especially for healthcare.

I don't currently have access to Visual Studio and I think I'd raise a few eyebrows if I asked for it. None of the coworkers in my office automate anything, mainly from lack knowledge I'm guessing. They are open to it though. They really enjoyed seeing how fast AutoIt could complete some of our mundane tasks.

wwb posted:

Does their software have the windows accessiblity hooks built in? Is it keyboard operable? Sendkeys is fun and easy and the way we used to do this poo poo before we had newfangled crap like coded ui.

I'm not sure. I'd get blank looks if I asked anyone I have access to. I'm new, and testing/automating is a small part of my responsibilities so I don't want to come off as overzealous yet. However, poking around it looks like the coding for the iforms we use are in html and javascript.

Didn't mean to hijack the powershell thread but I appreciate the inputs.

Hughmoris fucked around with this message at 15:50 on Jul 29, 2014

Hughmoris
Apr 21, 2007
Let's go to the abyss!
I need to accomplish a task and I'm thinking powershell might be my only hope.

I need to schedule a task on 10 VMs, but I need to have it specific to a second. For example, at 08:40:15 I want to launch notepad.exe on VM1. Then at 08:40:20 I want to launch notepad.exe on VM2. Ideally, I'd like to sit at my workstation and use powershell to schedule the tasks.

What I have been doing is using the taskscheduler GUI but its clunky and takes forever to work my way through 10 VMs. I've tried learning more about SCHTASKS in command prompt but you can only schedule by the minute, you can't schedule by the second.

All computers will be running Windows 7. Can powershell handle something this or do I need to get more creative?


*I was thing maybe I could use the TaskScheduler GUI to create my task which will open notepad at 08:40:15. Then open powershell or command prompt and find that task, then copy it out to the other machines. Not sure if that would work. :smith:

Hughmoris fucked around with this message at 03:49 on Aug 16, 2014

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Dr. Arbitrary posted:

I'm away from my desk but I would start with get-help new-ScheduledTask -full

I'll test it out in a bit and see if I can get something to work.

How are you going to be getting the times? Can you make a csv with the VM and time?

I opened powershell, ran get-help new-ScheduledTask -full and receiver the error
code:
Get-Help: Cannot find help for topic "new-ScheduledTask
My workstation and all the VMs are running Powershell 2.0


I'm not positive what you mean about getting the times. It would run something like this:
code:
VM1      terrible_script.exe       08:05:00
VM2      terrible_script.exe       08:05:05
VM3      terrible_script.exe       08:05:10
VM4      terrible_script.exe       08:05:15
VM5      terrible_script.exe       08:05:20
VM6      terrible_script.exe       08:05:25
...
Odd question, might not make sense... When you create a task, is there a file/object created that can be copied to other machines?

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Dr. Arbitrary posted:

poo poo. I hate when that happens.
Maybe it can be done with .NET

I still want to make it work. This is a fun challenge.

I'll have to do it without installing any further software.

And you're right, while its irritating its also a fun brain puzzler. After googling, I'm thinking maybe create the task on all the machines using the command prompt for 08:00. Then somehow export the task which appears to be an XML, edit the XML to have the time be 08:00:05, then import it. Not sure if I'm going crazy after dealing with this all day.

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Dr. Arbitrary posted:

.Net is a prerequisite for powershell so that won't be a problem.

I think you might start with this:
http://letitknow.wordpress.com/2011/05/20/create-scheduled-task-by-using-powershell/

The key element is
$service = NewObject -ComObject("Schedule.Service")

You can then use
$Service | Get-Member
To find new properties.

This is pretty difficult territory for me so I'd just carefully look at the examples and try to work it out.

At first glance it looks like the site you listed could be a more elegant solution but I'm not too familiar with a lot of the code being used. So, I went about solving it like a caveman.

1. At my workstation, I create a local task in command-prompt:
code:
schtasks /create /tn test_task /tr notepad.exe /sc once /st 23:00
2. Now that the task is created for my local machine, I export it to a XML file:
code:
schtasks /query /xml /tn test_task > adjusted_test_task.xml
3. I edit that XML file in notepad to have a launch time of 23:00:05, then save

4. I then export that newly adjusted task file to each VM:
code:
schtasks /create /s vMachine1 /u hughmoris /p password /XML adjusted_test_task.xml /tn test_task
With this clumsy method, I'd have to do step 3 and 4 for each machine because I'd have to edit the XML file each time to increase the launch time by 5 seconds. However, that should be MUCH faster than going the the TaskScheduler GUI for each machine.


I tested it on 2 machines and it appears to work. Ugly but effective. I'm definitely ears for other solutions though.

Hughmoris fucked around with this message at 05:33 on Aug 16, 2014

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Ithaqua posted:

I've taken a similar approach (the COM stuff sucks). But why not use PowerShell to set the time in the XML instead of manually editing it?

This should work:

code:
$timeOffset = 0;
$machines = @("machine1", "machine2", "etc")
$xml = [xml](get-content adjusted_test_task.xml)

$initialTime = [DateTime]::Parse($xml.Task.Triggers.TimeTrigger.StartBoundary)

foreach ($machine in $machines) {
    $outputFile = $machine + "_adjusted_test_task.xml"
    $timeOffset += 5;
    $newTime = $initialTIme.AddSeconds($timeOffset);
    $xml.Task.Triggers.TimeTrigger.StartBoundary = $newTime.ToString("s")
    set-content $outputFile $xml.InnerXml
    schtasks /create /s $machine /u hughmoris /p password /XML $outputFile /tn test_task
}

Thanks for taking the time to do this. I don't know powershell but I think I can piece together whats happening. I'm going to try it out later tonight and I'll let you know how it works out.

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Hughmoris posted:

Thanks for taking the time to do this. I don't know powershell but I think I can piece together whats happening. I'm going to try it out later tonight and I'll let you know how it works out.

Just to follow up, I attempted to create this PS script. I was unable to run the script due to being restricted by the system. After a little reading, I tried to allow it with: set-executionpolicy remotesigned. Received the error that I couldn't alter the regkey. So, there goes that. Not sure if our IT department will unlocked that for me. Either way, the higher ups want to start all this crap at 0830 Monday morning so it won't do me much good.

I do have AutoIt installed on this workstation, so I guess I'll try and figure out how to write your script in AutoIt. Unless it would be easier to write some sort of command-prompt script.

Hughmoris
Apr 21, 2007
Let's go to the abyss!
Is there an easy way to print a PDF file to a network printer, using powershell? I couldn't find an easy way to do it, so right now I'm having the script make the network printer be the default printer, then print to default printer.

Hughmoris fucked around with this message at 20:23 on May 5, 2015

Hughmoris
Apr 21, 2007
Let's go to the abyss!
Ignore.

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Reiz posted:

Are you using powershell 4? Get-Printer and Out-Printer should probably do what you need. There's also the .Net System.Drawing.Printing namespace which you could use with some effort: https://msdn.microsoft.com/en-us/library/system.drawing.printing%28v=vs.110%29.aspx

I'm using Powershell 2. It's a work computer running Windows 7, and I'm a bit leery about trying to update powershell to a newer version. I'll have to take a look at that Namespace link you provided. The method I'm using now works but its a bit...awkward.

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Briantist posted:

What are your concerns about upgrading powershell? If you already have .Net 4 then you just need to install WMF 4 to get it.

I'm not too familiar with PS, and with it being a work computer I'm not sure if an upgrade would have a negative impact on anything else installed.

Hughmoris
Apr 21, 2007
Let's go to the abyss!
Kind of stumped here. I'm working with a CSV and following this technet tutorial.

My starting CSV is in this format:
code:
Facility ID, Pat Name,Pat Status,Account Number
FacilityA, Bob Bobby, Patient Active, 123456789
FacilityB, Henry Aaron, Patient Inactive, 23232323
Facility A, Babey Ruth, Patient Active, 565655656
I run this comman: Import-Csv c:\pwr_shell\testCSV.csv

and my output is this in this format:
code:
Facility ID    : A
Pat Name       : Bob Bobby
Pat Status     : Patient Active
Account Number : 123456789

Facility ID    : B
Pat Name       : Henry Aaron
Pat Status     : Patient Inactive
Account Number : 232323232

....
....
My problem is that I don't want that vertical format. I'd like it to display the header columns laterally instead of vertical, like the technet example:
code:
Name                       Department                 Title
----                       ----------                 -----
Pilar Ackerman             Research                   Manager
Jonathan Haas              Finance                    Finance Specialist
Ken Myer                   Finance                    Accountant
What am I missing here?

Hughmoris fucked around with this message at 03:17 on Jun 2, 2015

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Briantist posted:

The important thing to remember is that you have an object, with properties, and you can view and manipulate it as you see fit. The way it's displaying at the moment is in "List" format, probbaly because PowerShell determined it would fit better that way or be too crammed in a table.

But you can easily change that with Format-* cmdlets:

code:
$data = Import-Csv c:\pwr_shell\testCSV.csv

$data | Format-List
# $data | fl  <- Shorthand

$data | Format-Table
# $data | ft  <- Shorthand
If you want to display only certain columns, name them:
code:
$data | Format-Table 'Pat Name' , 'Pat Status'
Just remember that Format-* cmdlets should be the last item in your pipeline because they are for display only. You almost never want to assign the result of a Format-* cmdlet to a variable either.

You're the man! The solved my problem. Trying to fumble my way through automating some tasks at work and its amazing how easy PowerShell makes it.

A quick google search showed me how simple it is to incorporate regex into the Where-Object command:
code:
$data = Import-Csv c:\pwr_shell\testCSV.csv | Where-Object {$_.'Facility ID' -match "^B"}
That will show me results for only the patients at Facility B, which I can then pipe into a new CSV.

Hughmoris
Apr 21, 2007
Let's go to the abyss!
Powershell was giving me fits earlier today when trying to accomplish a simple task.

I have a file called patient.txt with contents similar to:
code:
Patient: Doe, John
Location: ICU
Account: 1234567890123
I was trying to write a very simple script that would read/regex the file, and output the patient location: ICU. What is the best way to approach simple regex captures in Powershell? I would post my code but unfortunately I left my laptop at work tonight.

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Ithaqua posted:

(get-content C:\temp\patient.txt) -match "^Location:+"

Output:
Location: ICU

Unless you want to find all of the patients where the location is ICU? Your question is poorly worded.

Sorry, the question was very poorly worded. Now that I my work laptop with me, here is my input file (with fake patient info):
code:
Patient:  WINTER, SNOW Facility:  X Location:  4W/248 Account Number:  1234567890  A  MRI ABDOMEN W/ CONTRAST has been ordered
blah blah blah
blah blah
blah blah blah
Patient:  TEST, APRIL1 Facility:  Y Location:  2E/244 Account Number:  9879878979  A  MRI ABDOMEN W/ CONTRAST has been ordered for this patient
An ideal output would be just the Location identifiers
code:
4W2
2E
How would you go about getting that? Once I can regex and capture the location identifier, I can do more work further in my script.

Hughmoris fucked around with this message at 02:36 on Jul 8, 2015

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Briantist posted:

I think I would do something like this:

code:
$Locations = Get-Content C:\temp\patient.txt | ForEach-Object {
    if ($_ -match 'Location:\s+(?<Location>[^/]+)') {
        $Matches['Location']
    }
 }
$Locations will contain an array of the locations. Of course instead of putting those in a variable, you could just do your work inside the if statement within the loop. However you want to handle it really.

RegEx breakdown:

  • \s+ matches 1 or more whitepsace characters.
  • () parentheses starts a capturing group. Here I'm using a named capture group by using (?<Name>pattern) to make it easier to refer to later.
  • [^/]+ this matches 1 or more characters that aren't a forward slash, and since this is the entire pattern inside the capture group, this is what will get stored.

Then it's just a matter of using the $Matches object and referring the capture group, either by number, or in this case by name.

You could do multiple capture groups (with multiple names) all in the one match, and refer back to all of them, so you could break down each line of this file into its components if you wanted (patient, location, facility, etc.).

Thanks for this.

Hughmoris
Apr 21, 2007
Let's go to the abyss!
Vague question but does anyone here use Powershell for things outside of sysadmin type work? For web scraping, text parsing, console applications etc...? I like exploring new languages but I'm not going to need it for any sort of administrator duties.

Hughmoris
Apr 21, 2007
Let's go to the abyss!
I need some help with getting powershell to display glyphs correctly. I'll preface this by saying I don't have a great grasp on fonts/glyphs/unicode.

I'm using powershell to execute some Perl 6 code. It is not properly displaying glyphs that are in the output. After some googling, I've installed Unifont and am using the Powershell ISE but it still fails to display properly. Here is what the output looks like:



Any ideas?

Hughmoris
Apr 21, 2007
Let's go to the abyss!

I'll give that a look. Thanks!

Hughmoris
Apr 21, 2007
Let's go to the abyss!
I need a little PS help.

Often times, but not always, IT will change the printer name but it will keep the same IP address. The application I support needs to work off the printer name, so I'll get a ticket saying "Hey, can you add this printer <name>". I'd like to search by IP address to see if it's the same physical printer but with just a different name.

What I need to do: Given a network printer name, how do I find out it's IP address? Or, given an IP address, how do I find the "friendly" name of the printer at that IP address?

The friendly name I'm looking for is the same name the user sees if they go into Windows 10 -> Settings -> Printers and Scanners.

Hughmoris
Apr 21, 2007
Let's go to the abyss!
I added irrelevant details, sorry.

In powershell, is there a command to get more info from a network printer if "nslookup <ipaddress>" doesn't return what I need?

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Bruegels Fuckbooks posted:

You tried some combination of Get-Printer and Get-PrinterPort?

I have. From what I can tell, that returns information on printers for the local machine. I'll hop over to the SH/SC printer thread and see if they have any ideas.

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Bruegels Fuckbooks posted:

it uses wmi so it can get printers from remote machines as well...


FISHMANPET posted:

Are your clients connecting directly to the printer's IP or connecting to a print queue on a server? I think you've got a process problem, not a technology the problem. There's no standard protocol of "printer names", you can go into the properties of a printer and just set the "name" to whatever. So my guess is that in your environment the printer name means something, and the fact that it can change means there's some kind of process for installing/updating printers on clients, and so you need to look into that business process to get an understanding of what a printer "name" means.

Fair enough. I don't know PS or enough details of the network printer setup (I think they are connecting to a print queue on a server) so I'm flailing a bit, was hoping for an easy solution to get around this people/process problem. IT is running the show, I'm just catching the downstream effects when things change and clinicians can't print properly out of the application.

I appreciate the help and will work on the process problem.

Hughmoris
Apr 21, 2007
Let's go to the abyss!
To wrap this up: since I can't leave well enough alone, I started poking about a bit more. When I ran Get-Printer on my local computer on the VPN, I saw that it had a printer mapped to a network path with a $PrintServerName. I then ran Get-Printer --ComputerName "$PrinterServerName" and that gave a list of printers with their "friendly" name and ports.

I then did a little more sleuthing to find the other relevant print server names. A few more checks and I found my target IP and printer.

At this point I'll read up on a little more PS, put together a simple script that will poll all of the print servers for their list of printers and then check to see if a given IP is in one of them and what the associated printer name is.

The bigger picture is that this is a people/process problem that is outside of my responsibilites but it was a fun puzzle to solve.

Thanks for the help everyone

Hughmoris
Apr 21, 2007
Let's go to the abyss!
A bit of a broad rookie question because I don't know what I don't know. I'm following some tutorials on Microsoft Entra ID. Instead of clicking through the portal, I want to complete the steps in PowerShell.

With PowerShell, should I be using the Microsoft Graph module? Is the AzureAD module being deprecated for Graph, or am I misunderstanding the random rear end blog articles I've found.

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Potato Salad posted:

I think you're overthinking this? If you want to make a new user, you cast New-AzureADUser. It....does that.

edit: I see what you're asking. Yes, install the graph module and get it connected with your tenant

I scrolled through these directions; they look like they should get you installed and connected

https://www.alitajran.com/install-microsoft-graph-powershell/

:hfive:

Thanks!

Hughmoris
Apr 21, 2007
Let's go to the abyss!
Rookie PowerShell question:

If I'm running PS commands from the CLI, how would I selectively log certain executed commands to a CSV? Not the output, just the command/script executed and the time.

In plain English, I think I need a My-Logger function so if I call: My-Logger Get-Process , it would append to my.csv the datetime and Get-Process.

I'm new to PS and not sure how to approach this.

Hughmoris
Apr 21, 2007
Let's go to the abyss!
Thanks for the ideas. I'm phone posting so forgive me.

What I need is an "on the fly" ad-hoc way of saying "I want to log to a custom CSV the command/script I'm about to execute". I don't have a need to log other stuff I run.

Maybe I can figure out a way to retroactively parse history for the info?

Hughmoris
Apr 21, 2007
Let's go to the abyss!
Thanks for the idea! I learned something new with that Start-Transcript.

It's a weird short-term thing that isn't totally necessary, just something that can save me a bit of manual data entry. I'm mainly poking at it to see if I can automate it.

At this point I'm thinking I can add a comment (e.g. ##LogThis!) at the end of each relevant command execution, then write a simple script that parses History and finds those comments, writing those commands to a CSV along with their execution time.

Adbot
ADBOT LOVES YOU

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Wizard of the Deep posted:

I'm still not seeing what exactly you're trying to accomplish. Do you need to submit some kind of report of when you do a specific task? In that case, I'd honestly just auto-start a transcript as part of your profile.ps1, then grab the relevant data whenever you need to submit the report. Combine that with a Posh theme that auto-timestamps your prompt and you're probably golden.

If you're trying to capture specific output from a command/script, adding | export-csv -NoClobber (or -Append) -NoTypeInformation -Path '$path\command-{$get-date}.csv' or similar code directly into your script is probably the right way to go.

Pile Of Garbage posted:

Is this potentially related to fulfilling some security thing (e.g. ACSC Essential Eight)? If so look at transcription/script block logging/module logging settings in Group Policy (Note you can enable these on a single machine via local Group Policy, aka gpedit.msc): https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_group_policy_settings?view=powershell-5.1

If you're looking to have a kind of running-log of your PowerShell session's execution history you could add a PSConsoleHostReadLine function to your Profile.ps1. There are various automatic variables that should allow you to pull out the relevant parts of what's about to be executed and write it to a file. Note that you can break your console with this if you do something like:

code:
function PSConsoleHostReadLine { $_ }
You could also maybe do the same thing by defining a custom prompt: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_prompts?view=powershell-5.1

Thanks for the ideas. I was attending an informal training session where certain actions needed to be logged for review. I ended up just keying in ,or copy/pasting, what was needed. I have learned more about the transcripts and profiles after reading up on your suggestions.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply