Mapping of process name and application name using powershell - powershell

I need to track foreground application with application name in window machine. I am using given code but it provide ProcessName not application name example ProcessName is "chrome" Apliication name is "Google Chrome". Either I get application name direclty or i able to mapped Application name with process name.Please help me into this
[CmdletBinding()]
Param(
)
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class UserWindows {
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
}
"#
try{
$ActiveHandle = [UserWindows]::GetForegroundWindow()
$Process = Get-Process | ? {$_.MainWindowHandle -eq $activeHandle}
$Process | Select ProcessName, #{Name="AppTitle";Expression= {($_.MainWindowTitle)}}
}catch{
Write-Error "Failed to get active Window details. More info:$_"
}

Rather than give you the answer (since you may have more questions after) I will teach to to fish for yourself.
Lets say you have a variable and you want to see all of its properties you can get from it; run $variable |get-member
Now you see there are a lot of properties attached to your variable and you don't see any called "application name". So lets list all of the properties of this variable and see what gives us the value we are looking for.
For my example I will grab chrome to put into my variable so we are on the same page.
Here is the code I used to grab the variable to match what you would be working with (ignore this if you already have your variable you're working with).
$variable= Get-Process|? name -ilike chrome|select -first 1
Lets list all the properties
$variable|format-list *
Now we see there are 2 properties that list the name were looking for, Description and Product (for chrome either works, but i don't know which will work for your other use cases, possibly none). Lets grab Product and use that for your code, substituting processname in the select statement (the statement that selects what properties to keep/show in that variable) with the Product Property... Now that you know how, you can change if need be =)
[CmdletBinding()]
Param(
)
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class UserWindows {
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
}
"#
try{
$ActiveHandle = [UserWindows]::GetForegroundWindow()
$Process = Get-Process | ? {$_.MainWindowHandle -eq $activeHandle}
$Process | Select Product, #{Name="AppTitle";Expression= {($_.MainWindowTitle)}}
}catch{
Write-Error "Failed to get active Window details. More info:$_"
}

Related

PowerShell Get process by its handle

$ActiveHandle = [UserWindows]::GetForegroundWindow()
$Process = Get-Process | ? {$_.MainWindowHandle -eq $ActiveHandle}
This code retrieves a title of the current active window. Problem is that it only filters processes by MainWindowHandle. For example, if my active handle is a popup from the same process, it doesn't return anything as the handle is not its main handle. How can I modify the code to check for ALL handles instead of just the main one? Or rather, how can I retrieve all process handles?
I do not want to use external tools like WASP.
You can use the GetWindowThreadProcessId Win32 API function for this:
# Define a type that allows us to call the relevant win32 api
$user32 = Add-Type -MemberDefinition #'
[DllImport("user32.dll", SetLastError=true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
'# -PassThru -Name user32Func
# prepare a variable to receive the target process id
$procId = 0
# call the function with, pass the handle as the first argument
$threadId = $user32::GetWindowThreadProcessId($ActiveHandle, [ref]$procId)
# If the owning thread and process was identified, the return-value will have been non-0
if($threadId) {
Write-Host "Found process $(Get-Process -Id $procId |% Name) with PID $procId"
}
else {
Write-Host "No owning process found"
}

Get foreground windows of windows explorer to retrieve the url

I think am close to the solution, or in the general ball park, but the way am calling the powershell might be part of the issue am calling the ps1 from a batch file, to
I want to have the user click a button and then have powershell get the url of the active window (EXPLORER.exe) - i did try to but the start/sleep command to check in the ISE but could get it to work :( could you help be out ?
Thank You
Set-ExecutionPolicy RemoteSigned
Param(
)
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class UserWindows {
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
}
"#
try {
$ActiveHandle = [UserWindows]::GetForegroundWindow()
$Process | Select LocationURL| select -ExpandProperty LocationURL -First 1 |
Tee-Object -Variable "dirvar"
} catch {
Write-Error "Failed to get active Window details. More Info: $_"
}
$dirvar1 = "$dirvar" -replace 'file:///', ''
echo "$dirvar1"
Start-Process "Z:\30_Sysadmin\ADB_LOADER_DIR\ADBDIR.bat" "$dirvar1"
You are going about it in a difficult way. There are helper functions. This lists all shell windows (Internet Explorer and Explorer windows). The object is an Internet Explorer object. See https://msdn.microsoft.com/en-us/library/aa752084(v=vs.85).aspx.
This is VBScript but COM calls are identical across all languages.
Set objShell = CreateObject("Shell.Application")
Set AllWindows = objShell.Windows
For Each window in AllWindows
window.Navigate "c:\"
msgbox window.locationURL
Next

Create powershell alias for . $profile

I want to create a set of aliases in a file that I can update, then invoke an alias aa so that the file executes and I am provided with the new aliases in the current session. Ultimately I wanted these aliases available automatically on PS startup so I am using C:\Users\Administrator\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 to put them in. Right now it looks like:
$psdir="C:\Users\Administrator\Documents\WindowsPowerShell"
function Reload-Profile{
# . ${profile} DOES NOT WORK
# Write-Host ${profile}
# Write-Host $profile
# powershell $profile DOES NOT WORK
# Get-ChildItem "${psdir}\*.ps1" | %{.$_} DOES NOT WORK
Write-Host "Custom PowerShell Environment Loaded"
}
function Edit-Profile
{
powershell_ise.exe $profile
}
Set-Alias show Get-ChildItem
Set-Alias show2 Get-ChildItem
Set-Alias aa Reload-Profile
Set-Alias ep Edit-Profile
How can I do this so that the aliases are loaded on startup, yet I can also update them with an aa alias and have them brought into the current session?
If the original author of the comment that contained the following code decides to post it as an answer, just add a comment to this answer and I will remove it. As it has been two days I don't really expect him to. Meanwhile this should give people a better idea of what is actually happening.
# https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/add-type
# Create a new cmdlet Reload-Profile using C# code and import it
Add-Type '
using System.Management.Automation;
using System.Management.Automation.Runspaces;
// https://msdn.microsoft.com/en-us/library/dd878294(v=vs.85).aspx
[Cmdlet("Reload", "Profile")]
public class ReloadProfileCmdlet : PSCmdlet {
protected override void EndProcessing()
{
// https://msdn.microsoft.com/en-us/library/ms568378(v=vs.85).aspx
// Runs $profile without parameters in the current context and displays the output and error
InvokeCommand.InvokeScript(". $profile", false, PipelineResultTypes.Output | PipelineResultTypes.Error, null);
}
}' -PassThru | Select -First 1 -ExpandProperty Assembly | Import-Module;
# Setup an alias for the new cmdlet
Set-Alias aa Reload-Profile
For better readability/highlighting the C# code standalone:
using System.Management.Automation;
using System.Management.Automation.Runspaces;
// https://msdn.microsoft.com/en-us/library/dd878294(v=vs.85).aspx
[Cmdlet("Reload", "Profile")]
public class ReloadProfileCmdlet : PSCmdlet {
protected override void EndProcessing()
{
// https://msdn.microsoft.com/en-us/library/ms568378(v=vs.85).aspx
// Runs $profile without parameters in the current context and displays the output and error
InvokeCommand.InvokeScript(". $profile", false, PipelineResultTypes.Output | PipelineResultTypes.Error, null);
}
}
The problem with your code is, that Reload-Profile is a function and when you invoke it, it will create new scope for itself. When you then invoke . $profile, it will not create new scope for profile, but it still be invoked inside Reload-Profile scope. Thus, when Reload-Profile ends, the scope will be discarded. So, you need to invoke Reload-Profile with dot invoke operator as well: . Reload-Profile or . aa, if you use alias.
I assume, your real question is "How to make aa command in a way, which does not require to use dot invoke operator?"
The answer will be to use compiled cmdlet instead of PowerShell function, because PowerShell does not create new scope for cmdlet invocation. That cmdlet can then invoke . $profile in current scope.
Add-Type #‘
using System.Management.Automation;
using System.Management.Automation.Runspaces;
[Cmdlet("Reload", "Profile")]
public class ReloadProfileCmdlet : PSCmdlet {
protected override void EndProcessing() {
InvokeCommand.InvokeScript(
". $profile",
false,
PipelineResultTypes.Output | PipelineResultTypes.Error,
null
);
}
}
’# -PassThru | Select -First 1 -ExpandProperty Assembly | Import-Module
Set-Alias aa Reload-Profile
P.S.
I recommend you to use different verb instead of Reload, because Reload is not included in a list of recommended verbs, thus Import-Module will issue warning, when you import Reload-Profile into your session.

How to execute a powershell script without stealing focus?

I made a powershell script that uses GetForegroundWindow() to identify which Window is the currently focused Window. Unfortunately, when the powershell script is executed (via Windows Task Scheduler or a hotkey), the script steals focus of the current foreground app; incorrectly using the Powershell window itself as the Foreground app, instead of the intended foreground app.
I even tried creating an EXE using PS2EXE "-noconsole" setting; however, the script still doesn't doesn't work.
Could someone please suggest a way to execute this script without changing focus of the current foreground Window?
My script code works during tests (ONLY if I add "Start-Sleep -s 5"; and, manually steal back the focus with alt-tab for the script to identify the correct foreground Window.
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class Tricks {
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
}
"#
function Set-WindowStyle {
param(
[Parameter()]
[ValidateSet('FORCEMINIMIZE', 'HIDE', 'MAXIMIZE', 'MINIMIZE', 'RESTORE',
'SHOW', 'SHOWDEFAULT', 'SHOWMAXIMIZED', 'SHOWMINIMIZED',
'SHOWMINNOACTIVE', 'SHOWNA', 'SHOWNOACTIVATE', 'SHOWNORMAL')]
$Style = 'SHOW',
[Parameter()]
$MainWindowHandle = (Get-Process -Id $pid).MainWindowHandle
)
$WindowStates = #{
FORCEMINIMIZE = 11; HIDE = 0
MAXIMIZE = 3; MINIMIZE = 6
RESTORE = 9; SHOW = 5
SHOWDEFAULT = 10; SHOWMAXIMIZED = 3
SHOWMINIMIZED = 2; SHOWMINNOACTIVE = 7
SHOWNA = 8; SHOWNOACTIVATE = 4
SHOWNORMAL = 1
}
Write-Verbose ("Set Window Style {1} on handle {0}" -f $MainWindowHandle, $($WindowStates[$style]))
$Win32ShowWindowAsync = Add-Type -memberDefinition #"
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
"# -name "Win32ShowWindowAsync" -namespace Win32Functions -passThru
$Win32ShowWindowAsync::ShowWindowAsync($MainWindowHandle, $WindowStates[$Style]) | Out-Null
}
$a = [tricks]::GetForegroundWindow()
$title = get-process | ? { $_.mainwindowhandle -eq $a }
$title2 = $title | select -ExpandProperty ProcessName
if ($title2 -eq 'Kodi'){
Set-WindowStyle MINIMIZE $a;
if (Get-Process -Name Yatse2) {(Get-Process -Name Yatse2).MainWindowHandle | foreach { Set-WindowStyle MINIMIZE $_ }}
} ELSE {
$title.CloseMainWindow()
}
I know this question is old, but I've spent quite some time trying to figure out how to not lose focus from the current window for myself and found some information, so hopefully this will help future readers.
The easiest solution is just to literally simulate an Alt+Tab keypress from within your Powershell script instead of having to do it yourself. The following code comes from this StackOverflow answer:
[void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
[System.Windows.Forms.SendKeys]::SendWait("%{TAB}")
# Retrieve the window handles...
...where % represents the Alt modifier and {TAB} is interpreted as the tab key.
User homersimpson's answer works, but using reflection is a bit slow. You can speed things up by adding the Windows.Forms assembly directly...
Add-Type -AssemblyName System.Windows.Forms
...other imports
#Return focus to the original window.
[System.Windows.Forms.SendKeys]::SendWait("%{TAB}")
...Your Code Here
Again, the % represents Alt and you know what TAB is. You are effectively Alt-Tabbing the new window away, returning focus to your desired one.
Create task that can be run on demand in Task Scheduler and executes your powershell script
Make sure it is set to be run whether user is logged on or not
Create a shortcut that starts the task
That allows your script to be run without visible window

How can I use powershell to call SHGetKnownFolderPath?

I'm a total noob on windows powershell.
How can I use psl to call SHGetKnownFolderPath ?
I want to then also call SHSetKnownFolderPath if I dont like some of the values back from Get call.
You can use P/Invoke. Lee Holmes has an example of how to do this from PowerShell here. There's an example of how to use SHGetKnownFolderPoath here.
Alternatively, you might just be able to use Environment.GetFolderPath:
PS> [Environment]::GetFolderPath('CommonApplicationData')
C:\ProgramData
You can get the list of available options by the following:
PS> [Enum]::GetNames([Environment+SpecialFolder])
Before you delve into static methods in the Framework, look at the variables in the Env: PSDrive.
get-childitem env:
(get-item env:\CommonProgramFiles).Value
According to this Tutorial (and others) the settings are in the registry:
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders]
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders]
Those are an easy read in powershell, access them as a drive:
ps> cd hkcu:\Software\Microsoft\Windows\CurrentVersion\Explorer\
ps> dir
And use the standard powershell tools to read these settings.
NOTE: You can set them with powershell here however that might ruin your day.
If you use the explorer to change the directory, it also moves the directory and stores the settings on multiple locations, like both 'User Shell Folders' and 'Shell Folders'.
Here's a function you can use that will use SHGetKnownFolderPath to convert a well-known folder guid to its current path:
Function GetKnownFolder([string]$KnownFolderCLSID) {
$KnownFolderCLSID = $KnownFolderCLSID.Replace("{", "").Replace("}", "")
$GetSignature = #'
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]public extern static int SHGetKnownFolderPath(
ref Guid folderId,
uint flags,
IntPtr token,
out IntPtr pszProfilePath);
'#
$GetType = Add-Type -MemberDefinition $GetSignature -Name 'GetKnownFolders' -Namespace 'SHGetKnownFolderPath' -Using "System.Text" -PassThru -ErrorAction SilentlyContinue
$ptr = [intptr]::Zero
[void]$GetType::SHGetKnownFolderPath([Ref]"$KnownFolderCLSID", 0, 0, [ref]$ptr)
$result = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($ptr)
[System.Runtime.InteropServices.Marshal]::FreeCoTaskMem($ptr)
return $result
}
Usage example:
GetKnownFolder "C4AA340D-F20F-4863-AFEF-F87EF2E6BA25"
Will return
C:\Users\Public\Desktop
Reference for Well-Known folder GUID's can be found at Microsoft