param($appname, $apptype, $winstate, $appargs) #apptype is either "modern" or "desktop" #appname is the name of the app to be launched. In the case of a modern app is the name on the tile, and for a desktop app is either the name of the application included in the path (such as calc) or the full pathname (such as %windir%\system32\calc.exe) #winstate is either "Normal" (default), "Hidden", "Minimized" or "Maximized" #appargs allows parameters to be passed to the desktop applications #the windows modern app launch code included code from the MetroApps module by Tome Tanasovski #the desktop app launch code included come from some dude on the internetz $code = @" using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Win8 { public enum ActivateOptions { None = 0x00000000, // No flags set DesignMode = 0x00000001, // The application is being activated for design mode, and thus will not be able to // to create an immersive window. Window creation must be done by design tools which // load the necessary components by communicating with a designer-specified service on // the site chain established on the activation manager. The splash screen normally // shown when an application is activated will also not appear. Most activations // will not use this flag. NoErrorUI = 0x00000002, // Do not show an error dialog if the app fails to activate. NoSplashScreen = 0x00000004, // Do not show the splash screen when activating the app. } [ComImport, Guid("2e941141-7f97-4756-ba1d-9decde894a3d"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IApplicationActivationManager { // Activates the specified immersive application for the "Launch" contract, passing the provided arguments // string into the application. Callers can obtain the process Id of the application instance fulfilling this contract. IntPtr ActivateApplication([In] String appUserModelId, [In] String arguments, [In] ActivateOptions options, [Out] out UInt32 processId); IntPtr ActivateForFile([In] String appUserModelId, [In] IntPtr /*IShellItemArray* */ itemArray, [In] String verb, [Out] out UInt32 processId); IntPtr ActivateForProtocol([In] String appUserModelId, [In] IntPtr /* IShellItemArray* */itemArray, [Out] out UInt32 processId); } [ComImport, Guid("45BA127D-10A8-46EA-8AB7-56EA9078943C")]//Application Activation Manager public class ApplicationActivationManager : IApplicationActivationManager { [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)/*, PreserveSig*/] public extern IntPtr ActivateApplication([In] String appUserModelId, [In] String arguments, [In] ActivateOptions options, [Out] out UInt32 processId); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] public extern IntPtr ActivateForFile([In] String appUserModelId, [In] IntPtr /*IShellItemArray* */ itemArray, [In] String verb, [Out] out UInt32 processId); [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] public extern IntPtr ActivateForProtocol([In] String appUserModelId, [In] IntPtr /* IShellItemArray* */itemArray, [Out] out UInt32 processId); } } "@ add-type -TypeDefinition $code #function to return required package details from the manifest xml function PackageDetails ($pname) { [hashtable]$appdetails = @{} #retrieve xml data about the requested package $xml = Get-AppxPackage | Where-Object {$_.PackageFullName -eq $pname } | Get-AppxPackageManifest #retrieve appID and Displayname from XML - we need the appID for launching, Display Name (the name the programmer has given the app) and Visual Element Displayname (the name you see on the tile). $appdetails.appID = $xml.Package.Applications.Application.Id $appdetails.Appname = $xml.Package.Properties.Displayname $appdetails.DisplayName = $xml.Package.Applications.Application.VisualElements.Displayname $appdetails.IdentityName = $xml.Package.Identity.Name #return array of app details Return $appdetails } function FindModernApp ($appname) #this function searches the installed modern apps on the system to find the correct appID { $index=0 #Retrieve entire list of applications $applist=Get-AppxPackage #step through the list of installed applications and retrieve their details from the manifest xml. #keep in mind that not all applications are referenced by (in manifest.xml) "Package.Properties.Displayname", #you also may need to check "Package.Applications.Application.VisualElements.Displayname" and "Package.Identity.Name" foreach ($app in $applist) { #retrieve the app info from the manifest xml $appdetails = PackageDetails $($app.PackageFullName) #write-host "ID=" $appdetails.AppID ", Appname=" $appdetails.Appname ",Displayname=" $appdetails.DisplayName ",Identityname=" $appdetails.IdentityName IF ($appdetails.appID.count -gt 1) { foreach ($appIDelement in $appdetails.appID) { IF ($appIDelement -match $appname) { $correctappID = $($appIDelement) } } $appdetails.appID = $correctappID } #this is where we check all of the likely fields for the correct name... ( IF ($appdetails.appID -match $appname -or $appdetails.appID -match $appname.Replace(" ", "")) { #$appshortname = $($app.name) $appID = "$($app.PackageFamilyName)!$($Appdetails.appID)" $index++ } ElSEIF ($appdetails.name -match $appname -or $appdetails.name -match $appname.Replace(" ", "")) { #$appshortname = $($app.name) $appID = "$($app.PackageFamilyName)!$($Appdetails.appID)" $index++ } ELSEIF ($appdetails.DisplayName -match $appname -or $appdetails.DisplayName -match $appname.Replace(" ", "")) { #$appshortname = $($app.name) $appID = "$($app.PackageFamilyName)!$($Appdetails.appID)" $index++ } ELSEIF ($appdetails.IdentityName -match $appname -or $appdetails.IdentityName -match $appname.Replace(" ", "")) { #$appshortname = $($app.name) $appID = "$($app.PackageFamilyName)!$($Appdetails.appID)" $index++ } } Return $appID } function StartModernApp ($appID) #This function launches the Windows 8 modern app by the application ID. { [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)] $app = new-object Win8.ApplicationActivationManager $app.ActivateApplication($appID,$null,[Win8.ActivateOptions]::None,[ref]0) } function StartDesktopApp ($appname,$appargs,$winstate) # this function launches the desktop apps with the arguments using start-process. #I have noticed in some cases that when lauching apps through scripts, they don't always launch in the foreground. This method waits for the app to launch and forces it to be restored using the MainWindowHandle. { $app = Start-Process $appname -ArgumentList $appargs -WindowStyle $winstate -passthru #need to wait for the process to start start-sleep 1 $WinStateInt = $winstate switch ($WinStateInt) { "Hidden" {$WinStateInt = 0} "Normal" {$WinStateInt = 1} #"ShowMinimized" {$WinStateInt = 2} "Maximized" {$WinStateInt = 3} "ShowNoActivate" {$WinStateInt = 4} #"Show" {$WinStateInt = 5} "Minimized" {$WinStateInt = 6} #"ShowMinNoActive" {$WinStateInt = 7} #"ShowNA" {$WinStateInt = 8} #"Restore" {$WinStateInt = 9} #"ShowDefault" {$WinStateInt = 10} #"ForceMinimize" {$WinStateInt = 11} } $sig = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' Add-Type -MemberDefinition $sig -name NativeMethods -namespace Win32 [Win32.NativeMethods]::ShowWindowAsync($app.MainWindowHandle, $WinstateInt) } #main code starts here #note, the two types of supported apps are modern and desktop. #when launching a modern app, the appID must be retrieved and used for launch #keep in mind that due to inconsistancies in how modern apps are referenced, you will need to search for the app in a number of different ways, primarily this app uses the name on the tile (visual display name) #when launching a desktop app, the Process ID is retrieved and once the app has been launched, it is automatically brough to the front, due to the behaviour of some apps #the $appargs are optional and passed straight through to the desktop application at launch time #minimize Powershell script $sig = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' Add-Type -MemberDefinition $sig -name NativeMethods -namespace Win32 $PSId = @(Get-Process "powershell" -ErrorAction SilentlyContinue)[0].MainWindowHandle If ($PSId -ne $NULL) { [Win32.NativeMethods]::ShowWindowAsync($PSId, 2)} #clear appID $appID = "" #for testing #$appname = "wibble" #$apptype = "modern" #set the default window state to normal IF (-not $winstate) { $winstate = "Normal" } #note arguments cannot be NULL / blank so set them to (space) - this is easier than checking for NULLs later, or me just being lazy. IF (-not $appargs) { $appargs = " " } IF ($apptype.ToUpper() -eq "DESKTOP") { StartDesktopApp $appname $appargs $winstate } ELSEIF ($apptype.ToUpper() -eq "MODERN") { #get the appID for launching $appID = FindModernApp $appname #make sure we actually found the app! IF (-not $appID) { #Write-Host "Warning, no apps with the name '$appName' were found!" $URLERROR = "http://localhost:10561/player/readerId/ERROR" $URLVar = "http://localhost:10561/player/command/RunScript?1=Player.SetVariable(ErrorText, %22The application is not installed on this system, please see attendant%22)" $username = "ebc" $password = "Cloud_33" $domain = "" $webclient = new-object System.Net.WebClient $webclient.Credentials = new-object System.Net.NetworkCredential($username, $password, $domain) $webpage = $webclient.DownloadString($URLVar) $webpage = $webclient.DownloadString($URLERROR) } ELSE { write-host "Found app '$appname', id: $appID" #pause StartModernApp $appID $URL = "http://localhost:10561/player/command/RunScript?1=Player.SetVariable(SpinTime, 0)" $username = "ebc" $password = "Cloud_33" $domain = "" $webclient = new-object System.Net.WebClient $webclient.Credentials = new-object System.Net.NetworkCredential($username, $password, $domain) $webpage = $webclient.DownloadString($URL) } } ELSE { $URLERROR = "http://localhost:10561/player/readerId/ERROR" $URLVar = "http://localhost:10561/player/command/RunScript?1=Player.SetVariable(ErrorText, %22The application is not supported on this system, please see attendant%22)" $username = "ebc" $password = "Cloud_33" $domain = "" $webclient = new-object System.Net.WebClient $webclient.Credentials = new-object System.Net.NetworkCredential($username, $password, $domain) $webpage = $webclient.DownloadString($URLVar) $webpage = $webclient.DownloadString($URLERROR) #Write-Host "Application type $apptype not supported" #pause }