How to open and save/close file using powershell - powershell

I'm looking to create a hotkey on F10 that will, when pressed, open a text file named Notes. That is the simple part, it is:
C:\Users\Matt\Notes.txt
But I also want another press of the same hotkey to save the file and exit.
I am only interested in the script, I can run powershell through hotkeys.

Firing off an editor from script is as simple as:
$proc = Start-Process -FilePath C:\Bin\Notepad++.exe -arg C:\Users\Matt\Notes.txt -PassThru
The trickier part is figuring out how to save & close the file. If the editor happens to have a COM object model, you could use that but I doubt your editor is Word. :-)
Another general approach is to use WinForms SendKeys functionality. However an even better approach is to use the Windows UI Automation framework to drive the UI of arbitrary apps. There's even a PowerShell module that wraps this API to make it easy to use from PowerShell. It is called UIAutomation. Here is an example of how it is used:
Start-Process calc -PassThru | Get-UIAWindow |
Get-UIAButton -Name [1-3] | Invoke-UIAButtonClick;
You would substitute $proc for the Start-Process calc -PassThru bit above.

Related

Changing the caption permanently

In my script, I start a third-party non-GUI application. I'm sort of trying to run this embedded in my script itself, so I will be able to change the icon and the windows caption.
I have two restriction:
I have to use & 'application.exe' to start the application. I tested Start-Process -NoNewWindow, but that breaks the functionality of application.exe.
The application.exe needs to be running in my script. I can only change the icon when I compile my script with PS1 to Exe afterwards.
The challenge I'm now facing is related to the first restriction. I need to change the caption a-synchronously. The $host.ui.RawUI.WindowTitle = “New Title” is not working, because application.exe changes the caption right after execution. So I need to change it by using functions like SetWindowText(). This is working in VB.NET, but I'm looking for a way to start this function in parallel with the & 'application.exe'. When I use &, the application is executed and the script waits until it terminates. So I need to do the SetWindowText() in parallel.
Visual Basic/C has a BackgroundWorker functions for such cases. Is something like that also available in PowerShell?
Thanks for any help in advance!
Kind regards,
Eric
Everybody thank you very much for your help!
The solution proved to be a lot easier that I thought. You don't have to keep on renaming the window. You just have to start the cmd window, wait a bit (in the background it's doing something with conhost.exe) and then rename it once. Here's the code I used:
$titletext = "My New CMD Window Title"
# Start a thread job to change the window title to $titletext
$null = Start-ThreadJob { param( $rawUI, $windowTitle )
Start-Sleep -s 2 #Wait until cmd.exe is started
if ( $rawUI.WindowTitle -ne $windowTitle ) {
$rawUI.WindowTitle = $windowTitle
}
} -ArgumentList $host.ui.RawUI, $titletext
& 'c:\windows\system32\cmd.exe'
Kind regards,
Eric

Powershell SendKeys No Input

I'm working on a dual pc stream setup and would like to use my elgato stream deck on my gaming pc for some specific functions. The only problem is, no obs control. I was combing through reddit and came across the suggestion to use SendKeys in powershell scripts to perform hotkey functions. I am able to connect the two computers through PSSession and run my script, but nothing happens. I have the application focused. Even when I just open a text file and run the script, nothing comes up. I don't really think this should be that hard should it? Any help would be appreciated.
$wshell = New-Object -ComObject wscript.shell; $wshell.SendKeys(']')
Continuing from my comment...
Sendkeys is a thing but can be really finicky, focus, timing issues, etc. GUI automation is not really PowerShell's strong suit. Custom tools like AutoIT, Selenium, etc., are better options.
With Sendkeys, you often must set delays to ensure focus before calling keystrokes.
YOu can also avoid the use of ...
New-Object -ComObject wscript.shell
... and use this...
Add-Type -AssemblyName System.Windows.Forms
Here are a few examples you can try.
# pops the WinKey Start Menu
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait('^{ESC}')
Or this way...
# Initialize a variable with the .Net namespace, then use it.
$SendKeys = [System.Windows.Forms.SendKeys]
$SendKeys::SendWait('^{ESC}')
# SendKeys to hold down keys
$SendKeys::SendWait('q(+%) + (+)q')
# Send commnad results to notepad - Note the sleep to wait for notepad to open, paste the content then select the file menu
Get-NetIPConfiguration | clip | notepad
Sleep -Seconds 1
$SendKeys::SendWait('^V')
Sleep -Seconds 2
$SendKeys::SendWait('%F')
Update as per our comments below:
SendKeys requires a GUI up and running. A GUI requires a logged-on, interactive user.

Powershell Command vs Variable Formatting

I'm playing around with some Powershell commands and implementing them into scripts.
I noticed something that I cannot find much information on despite looking for a few hours so maybe you can help me here. This could also be lack of me searching for the wrong things, apologies ahead if that is the case.
What I'm experimenting with here is manipulating services through PS. Namely, for now, just getting the TaskName. Here is what I am doing:
PS C:\WINDOWS\system32> Get-ScheduledTask -TaskName 'Adobe*' | Select -ExpandProperty TaskName
Output:
Adobe Acrobat Update Task
Adobe Flash Player NPAPI Notifier
Adobe Uninstaller
This is all well and good. However, if I assign that command to a variable from within a powershell script and run the script:
$TaskNames = Get-ScheduledTask -TaskName 'Adobe*' | Select -ExpandProperty TaskName
Output:
Adobe Acrobat Update Task Adobe Flash Player NPAPI Notifier Adobe Uninstaller
So my questions here are:
Why does the formatting change when assigning the command to a variable and calling that variable as opposed to just writing the command explicitly
How can I get the variable call to format output as if I'm just typing the command in the first example
$TaskNames -join "`n"
... it's doing this probably because one is output of an object, and one is output of an array. If you do $TaskNames.getType() it should tell you it's an array. -join displays an array joined by whatever character you specify.

Generating printer shortcuts from list

I am trying to generate a shortcut for every printer I have on a print server. The idea is to be able to email these shortcuts to people and when they click on them, it automatically installs that printer for them.
I've populated an array from a list of printer names exported from the print server:
$list = #((get-contnet $home\dekstop\plist.txt))
I then created a method to create a shortcut:
function Make-Shortcut
{
param ([string]$dest, [string]$source)
$WshShell = New-Object -comObject Wscript.Shell
$Shortcut = $WshShell.CreateShortcut($dest)
$Shortcut.TargetPath = $Source
$Shortcut.Save()
}
The function works fine. I was able to create standard shortcuts with no problem.
This next part is where I am getting stuck:
foreach ($i in $list)
{
Make-Shortcut "C:\pshort\$i.lnk" "C:\Windows\System32\rundll32.exe
printui.dll,PrintUIEntry /in /q /n\\printserver\$i"
}
When this runs, it does generate a shortcut with the same name as the printer for each printer on the list. However, the problem comes in at the target path. Instead of
C:\Windows\System32\rundll32.exe printui.dll,PrintUIEntry /in /q /n\\printserver\printername
it changes it to:
C:\Windows\System32\rundll32.exe printui.dll,PrintUIEntry \in \q \n\printserver\printername
The three problems with this are:
It is reversing the forward slash for the parameters
It is removing one of the backslashes preceding the server name
It is adding quotes to both sides. I need the quotes to come off for the shortcut to work properly.
I assume this is happening because Powershell thinks I am trying to make a standard shortcut and thinks I made mistakes while typing out the path.
I have tried putting a ` in front of each forward slash hoping the escape character would prevent it from reversing it, but no luck. I also tried using a hyphen for each parameter but that did not work either.
Is there anyway to stop this from happening? Or is there perhaps a better way to try to accomplish what I am trying to do?
You need to add arguments to the com object
Try adding a new param $arguments to your Make-Shortcut function and do:
Make-Shortcut "C:\pshort\$i.lnk" "C:\Windows\System32\rundll32.exe"
"printui.dll,PrintUIEntry /in /q /n\\printserver\$i"
add this in your function:
$Shortcut.Arguments = $arguments
So the link is created successfully ... but I have no idea if it works :)
Completely different answer but in a standard windows environment simply clicking a hyperlink to \printserver\printer will add a shared printer to someone's system?
So an email that simply lists :
\\PrintServer\Printer01
\\PrintServer\Printer02
\\PrintServer\Printer03
Would probably do the job just as well.

Can I write PowerShell history to a text file on PowerShell exit?

I am curious to know if we can do this in Powershell.
with Out-File command we can pipe it to get output written to a file. That way I can send all my history commands to a text file.
The Question is Can I send my history commands to a text file every time I exit?
I don't know if this would be of big help but sometimes if you wrote some one liners and you quit the PS console accidentally then all the history commands will be saved to a text file just like recent chat conversations.
You can use start-transcript -path .\console.txt -append in you $profile to have in a txt file all console actions, not just the History but the returns of the commands too.
Another possibility:
function start-histcap {
clear-history
$host.enternestedprompt()
get-history | out-file c:\testfiles\commandhist.txt -append
}
Run start-histcap, and you'll be at a nested prompt. Whatever you do there will get written to the history file when you exit that nested prompt.
Its hard to always catch an "exit". you can register for the onexit event but the problem is that will ONLY catch when a user types "exit" not if they hit the X or close in any other way..
Powershell profile "on exit" event?
so in the action event you just do get-history (specify a number if you need more than the default 100) and then set-content to a file...
you might be better off using Start-Transcript, but that only works in Console..