I've created a script that will automatically initiate a video call with a user of my choice.
When ran, the script leaves the video call docked, with the lync video call window flashing.
How would I be able to get this window to maximize and go to full screen when the script is ran?
Thank you so much for your help.
Below is my code
$assemblyPath = “C:\Program Files (x86)\Microsoft Office 2013\LyncSDK\Assemblies\Desktop\Microsoft.Lync.Model.DLL”
Import-Module $assemblyPath
$LyncClient = [Microsoft.Lync.Model.LyncClient]::GetClient()
$StartVideoCallMethod = {
$Conversation = $this.ConversationManager.AddConversation();
$contact = $LyncClient.ContactManager.GetContactByUri("useremailhere")
[void]$Conversation.AddParticipant($contact);
[void]$Conversation.Modalities['AudioVideo'].BeginConnect({}, 0);
};
Add-Member -InputObject $LyncClient -MemberType ScriptMethod -Name StartVideoCall -Value $StartVideoCallMethod -Force;
# Initiate the video call
$Conversation = $LyncClient.StartVideoCall();
I don't have Lync, but something like this should work. I'm using the process name (or what I'm guessing it is) to get the MainWindowHandle for the Lync window, then sending that a command to maximize (cmd=3, see here for the full list of values: https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548%28v=vs.85%29.aspx).
This code may break if more than one process matches by name, but it should get you started; if you can get the PID or some other, better unique identifier, use that. Just mess around with the output of Get-Process and you should see a number of options, and remember you can always use a Where clause to filter the output. Or of course if there's some way to get the MainWindowHandle directly from $LyncClient, even better.
$w = Get-Process -Name "Lync"
$Win32ShowWindowAsync = Add-Type –memberDefinition `
'[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' `
-name “Win32ShowWindowAsync” -namespace Win32Functions –passThru
$Win32ShowWindowAsync::ShowWindowAsync($w.MainWindowHandle,3) | Out-Null
Here the code that I have so far.
Still needs some tweaks to perfect it but it does the job.
Tweaks would be specifying which window to maximize as it will sometimes maximize the lync contacts window.
Code
$assemblyPath = “C:\Program Files (x86)\Microsoft Office 2013\LyncSDK\Assemblies\Desktop\Microsoft.Lync.Model.DLL”
Import-Module $assemblyPath
$exePath = "C:\Program Files\Microsoft Office 15\root\office15\lync.exe"
if(!(get-process | ?{$_.path -eq $exePath})){
Start-Process -FilePath $exePath -WindowStyle Maximized
Start-Sleep -s 10
}
$LyncClient = [Microsoft.Lync.Model.LyncClient]::GetClient()
$StartVideoCallMethod = {
$Conversation = $this.ConversationManager.AddConversation();
$contact = $LyncClient.ContactManager.GetContactByUri("ernesto.gomila#quirchfoods.com")
[void]$Conversation.AddParticipant($contact);
[void]$Conversation.Modalities['AudioVideo'].BeginConnect({}, 0);
};
Add-Member -InputObject $LyncClient -MemberType ScriptMethod -Name StartVideoCall -Value $StartVideoCallMethod -Force;
# Initiate the video call
$Conversation = $LyncClient.StartVideoCall();
#Maximize window
$w = Get-Process -Name "lync"
$Win32ShowWindowAsync = Add-Type –memberDefinition #"
[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
"# -name “Win32ShowWindowAsync” -namespace Win32Functions –passThru
Start-Sleep -s 2
$Win32ShowWindowAsync::ShowWindowAsync($w.MainWindowHandle,3) | Out-Null
Related
I'm re-writting a batch file that combined powershell and cmd commands to be strictly a powershell script, and I'm looking for a way to minimize/close the API confirmation window which pops up in the user's web browser after the application the script calls on starts.
My original batch file code looked like this using a shell object to minimize everything before moving on to the next command:
cd /d "%userprofile%\Desktop\streamblastoff\libraries\binaries\Snip"
start Snip.exe
timeout /t 1 /nobreak
powershell -command "(new-object -com shell.application).minimizeall()"
And this is what I have so far:
Push-Location -Path $PSScriptRoot\libraries\binaries\snip
Start-Process .\Snip.exe; (new-object -com shell.application).minimizeall()
Pop-Location
It doesn't work though, everything minimizes before the browser window appears ... which I guess I should have seen coming. Ideally I'd like to do it all a bit cleaner in my new script, and be able to close/minimize the specific tab once the window pops up in the users default browser, but I'm not sure if that'd be possible ...
needing to minimize a users default browser window after the first application starts
# First application.
$bar = "powershell"
# First application starts.
Start-Process -FilePath $bar
# Get Default Browser
$foo = Get-ItemPropertyValue -Path "Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice" -Name 'ProgId' |
ForEach-Object {
Get-ItemPropertyValue -Path "Registry::HKEY_CLASSES_ROOT\$_\shell\open\command" -Name '(default)'
} |
ForEach-Object {
$_ -match '^"([^"]+\.exe)"' | Out-Null
$matches[1]
} |
ForEach-Object {
Get-Item -Path $_
} |
ForEach-Object {
$_.BaseName
}
# End Get Default Browser
Function minimizeProcess
{
Param(
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
HelpMessage="Input a System.Diagnostics.Process object.")]
[System.Diagnostics.Process] $Process
)
Begin
{
# P/Invoke Definition
$signature = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
# Compile new class.
$myType = Add-Type -MemberDefinition $signature -Name MyClass -Namespace MyNamespace -PassThru
}
Process
{
# Minimize the window.
# For different display actions see:
# https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
$myType::ShowWindowAsync($Process.MainWindowHandle, 7) | Out-Null
}
}
# Minimize $foo if $bar is running.
if ((Get-Process | ForEach-Object { $_.Name }) -contains $bar)
{
Get-Process -Name $foo |
ForEach-Object {
$process = Get-CimInstance Win32_Process -Filter "ProcessID = '$($_.Id)'"
$owner = Invoke-CimMethod -InputObject $process -MethodName GetOwner
Add-Member -InputObject $_ -NotePropertyName Owner -NotePropertyValue $owner.User
$_
} |
# Only minimize processes that belong to the user.
Where-Object { $_.Owner -like $env:USERNAME } |
ForEach-Object {
minimizeProcess $_
# foo minimizes.
}
}
PowerShell cmdlet to open a URL in the user's default browser. · GitHub
How to find the default browser via the registry on Windows 10 - Stack Overflow
PowerShell P/Invoke Walkthrough | Precision Computing
Add-Type (Microsoft.PowerShell.Utility) - PowerShell | Microsoft Docs
Process.WaitForInputIdle Method (System.Diagnostics) | Microsoft Docs
Process.MainWindowHandle Property (System.Diagnostics) | Microsoft Docs
ShowWindowAsync function (winuser.h) - Win32 apps | Microsoft Docs
powershell - Get-Process and Process Owner - Stack Overflow
.net - How do I determine the owner of a process in C#? - Stack Overflow
everything minimizes before the browser window appears
The error you were making was you did not copy the sleep.
Push-Location -Path $PSScriptRoot\libraries\binaries\snip
Start-Process .\Snip.exe
# timeout /t 1 /nobreak
Start-Sleep 1
(new-object -com shell.application).minimizeall()
Pop-Location
When creating macros, you have to insert sleeps to accommodate delays in the graphical user interface.
Start-Sleep (Microsoft.PowerShell.Utility) - PowerShell | Microsoft Docs
Timeout - delay in seconds - Windows CMD - SS64.com
be able to close/minimize the specific tab
SeleniumHQ Browser Automation
I've got a collection of powershell scripts, some of which call others. Some of these subscripts can also be called on their own as needed. How can I quickly add logging to all of the scripts so that any script invocation results in a log file for later examination?
There are a number of questions dealing with logging with some great answers, like this one. But I wanted to see what we could come up with that:
required minimal touching of the existing powershell files
automatically dealt with script A.ps1 calling script B.ps1. If you call
A.ps1, A.ps1 needs to start and finish the logging. But if you call B.ps1
directly, B.ps1 does.
I came up with my answer below, and wanted to share and see if there were other ideas on how to approach this, or suggestions for improvement on my answer.
The support code I write (further down) allows for just adding the following to each ps1 file. It automatically gives me logging regardless of if a script is called at top-level or by another script:
#any params for script
. "$PSScriptRoot\ps_support.ps1"
StartTranscriptIfAppropriate
try
{
#all of the original script
}
finally
{
ConditionalStopTranscript
}
The code that powers this is in ps_support.ps1, sitting next to my collection of powershell files that need logging. It uses Get-Variable and Set-Variable to manipulate a couple variables at the caller's scope level:
Logging__TranscriptStarted is normal so sub-scopes can see that
logging is already happening and not try to start it again.
Logging__TranscriptStartedPrivate is private so a scope can know if
it is responsible for stopping the logging.
Here is ps_support.ps1:
Set-Variable -name TranscriptStartedPropertyName -opt ReadOnly -value 'Logging__TranscriptStarted'
Set-Variable -name TranscriptStartedPrivatePropertyName -opt ReadOnly -value 'Logging__TranscriptStartedPrivate'
function StartTranscriptIfAppropriate
{
$transcriptStarted = [bool](Get-Variable -name $TranscriptStartedPropertyName -ErrorAction Ignore)
if (-not $transcriptStarted)
{
$callstack = get-pscallstack
$fullPath = $callstack[$callstack.count-2].ScriptName
$name = Split-Path -Path $fullPath -Leaf
$directory = Split-Path -Path $fullPath
$logDirectory = [IO.Path]::GetFullPath("$directory\..\scripts_logs")
md -force $logDirectory | out-null
$logFinalPath = "$logDirectory\$(Get-Date -Format o | foreach {$_ -replace ":", "."})_$name.log"
Set-Variable -scope 1 -name $TranscriptStartedPropertyName -value $True
Set-Variable -scope 1 -option private -name $TranscriptStartedPrivatePropertyName -value $True
Start-Transcript $logFinalPath | Write-Host
}
$immediateCallerPath = Get-Variable -scope 1 -name PSCommandPath -ValueOnly
Write-Host "Starting script at $immediateCallerPath"
}
function ConditionalStopTranscript
{
$immediateCallerPath = Get-Variable -scope 1 -name PSCommandPath -ValueOnly
Write-Host "Stopping script at $immediateCallerPath"
$transcriptStartedByMe = [bool](Get-Variable -scope 1 -name $TranscriptStartedPrivatePropertyName -ErrorAction Ignore)
if ($transcriptStartedByMe)
{
Stop-Transcript | Write-Host
}
}
I'm working on an automaton script for use by our end users in SCCM. Everything is working the way i want it to except for the section for launching outlook with the /cleanviews switch in a hidden window.
Current script section
$path = "C:\Program Files (x86)\Microsoft Office\root\Office16"
$path2 = "C:\Program Files\Microsoft Office\root\Office16"
Test-path $path
if($True){
Start-Process -workingdirectory $path OUTLOOK.EXE /cleanviews -WindowStyle Hidden -ErrorAction Ignore}
Else {
Start-Process -workingdirectory $path2 OUTLOOK.EXE /cleanviews -WindowStyle Hidden -ErrorAction Ignore}
Start-Sleep -s 15
get-process OUTLOOK -ErrorAction ignore | stop-process
Start-Sleep -s 5
I've also tried removing the -working directory portion, and moving -windowstyle from the end to directly after start-process. So far the application is launching in a normal window
There is another script section after this portion and the reason i don't want our users to see the second window during the cleanviews switch is because they could easily freak out with it closing again and or interrupt the script.
suggestions?
just to start, the
Test-path $path
if($True){}
bit makes no sense and will always return true, i'm assuming this was put in for testing?
Second, some applications will ignore the -WindowStyle part, you can however do this:
Start-Process -FilePath "C:\Program Files\Microsoft Office\root\Office16\OUTLOOK.EXE"
$Win32ShowWindowAsync = Add-Type –memberDefinition #”
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
“# -name “Win32ShowWindowAsync” -namespace Win32Functions –PassThru
$Show = 1 ; $Hide = 0 ; $TimeOut = 0
do{
Get-Process 'outlook' | % {
$Hidden = $Win32ShowWindowAsync::ShowWindowAsync($_.MainWindowHandle,$Hide)
}
Start-Sleep -Milliseconds 100
$TimeOut++
} while (!$Hidden -or $TimeOut -gt 100)
which is pretty ugly, but PowerShell doesn't have a native way to hide an existing process window.
I need to Take a screenshot with a script when a process has an error.
is there a way to minimize all windows, except the window of the process that got the error?
I know the way to minimize all:
$shell = new-object -com shell.application
$shell.MinimizeAll()
But is there a way to minimize everything except one window?
Thanks!
use API Windows
$Win32ShowWindowAsync = Add-Type –memberDefinition #”
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
“# -name “Win32ShowWindowAsync” -namespace Win32Functions –passThru
$titletowindow="TODO.csv - Bloc-notes"
get-process |
where mainwindowhandle -ne 0 |
%{if ($_.MainWindowTitle -eq $titletowindow) { $Win32ShowWindowAsync::ShowWindowAsync($_.MainWindowHandle, 3) | Out-Null} else { $Win32ShowWindowAsync::ShowWindowAsync($_.MainWindowHandle, 6) | Out-Null} }
I've been killing myself trying to get this to work on a remote computer, is it even possible? If so, can someone point me in the right direction?
Here's the code:
Function Lock-WorkStation {
#Requires -Version 2.0
$signature = #"
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
"#
$LockWorkStation = Add-Type -memberDefinition $signature -name "Win32LockWorkStation" -namespace Win32Functions -passthru
$LockWorkStation::LockWorkStation() | Out-Null
}
I can't test here, but for me it can NOT work because, as you can read in Microsoft documentation, the LockWorkStation function is callable only by processes running on the interactive desktop. In addition, the user must be logged on.
So when you connect to a remote computer using PSSession as far as I understand you are not in the interactive session.
Nothing to do with this, but it can help in Windows Vista/7 2008/R2, you can use the command tsdiscon.exe to lock a Remote Desktop session or your workstation.
Here is a sample where, logged as adminstrator domain on my computer, I first list, then lock the console session on my server.
PS> query session /server:WM2008R2ENT
SESSION UTILISATEUR ID ÉTAT TYPE PÉRIPHÉRIQUE
services 0 Déco
console jpb 2 Actif
PS> tsdiscon 2 /server:WM2008R2ENT
It's possible. But you need a workaround to connect to the interactive session.
Download the PowerShellPack and install it. You only need one module called "TaskScheduler".
I've tested the following code:
Function Lock-Workstation
{
param(
$Computername,
$Credential
)
if(!(get-module taskscheduler)){Import-Module TaskScheduler}
New-task -ComputerName $Computername -credential:$Credential |
Add-TaskTrigger -In (New-TimeSpan -Seconds 30) |
Add-TaskAction -Script `
{
$signature = #"
[DllImport("user32.dll", SetLastError = true)]
public static extern bool LockWorkStation();
"#
$LockWorkStation = Add-Type -memberDefinition $signature `
-name "Win32LockWorkStation" `
-namespace Win32Functions `
-passthru
$LockWorkStation::LockWorkStation() | Out-Null
} | Register-ScheduledTask TestTask -ComputerName $Computername `
-credential:$Credential
}
You can use it like this:
Lock-Workstation "NameOfTheComputer" (Get-Credential)
or like this:
Lock-Workstation "NameOfTheComputer"
If you receive an error in Connect-ToTaskScheduler when specifying a credential, it's because there is a typo in the module (edit Connect-ToTaskScheduler.ps1 and replace "$NetworkCredentail.Domain," with "$NetworkCredential.Domain,"