Lorenzo501

Minimized Tabs Outliner (wrapped .ps1).bat

Sep 6th, 2023 (edited)
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <# :: Batch Script Section
  2.  
  3. @powershell Invoke-Expression $([System.IO.File]::ReadAllText('%~f0'))
  4. @exit /b
  5.  
  6. #>
  7. # PowerShell Script Section
  8.  
  9. # this can likely be simplified for the specific use-case
  10. Add-Type -IgnoreWarnings -TypeDefinition @"
  11. using System;
  12. using System.Collections.Generic;
  13. using System.Diagnostics;
  14. using System.Linq;
  15. using System.Runtime.InteropServices;
  16. using System.Text;
  17.  
  18. namespace Win32 {
  19.    /// <summary>
  20.    /// Static class that lists all windows
  21.    /// </summary>
  22.    public static class WindowList {
  23.  
  24.        #region Call these to return window lists
  25.  
  26.        /// <summary>
  27.        /// Gets all windows with basic information: caption, class and handle.
  28.        /// The list starts with the desktop.
  29.        /// </summary>
  30.        /// <returns>WindowInformation list</returns>
  31.        public static List<WindowInformation> GetAllWindows() {
  32.            IntPtr desktopWindow = GetDesktopWindow();
  33.            List<WindowInformation> winInfo = new List<WindowInformation>();
  34.            winInfo.Add(winInfoGet(desktopWindow));
  35.            List<IntPtr> handles = getChildWindows(desktopWindow);
  36.            foreach (IntPtr handle in handles) {
  37.                try {
  38.                    winInfo.Add(winInfoGet(handle));
  39.                } catch (Exception ex) { }
  40.            }
  41.            return winInfo;
  42.        }
  43.  
  44.        /// <summary>
  45.        /// Gets all windows with extended information: caption, class, handle
  46.        /// parent, children, and siblings. The list starts with the desktop.
  47.        /// </summary>
  48.        /// <returns>WindowInformationList</returns>
  49.        public static List<WindowInformation> GetAllWindowsExtendedInfo() {
  50.            return winInfoExtendedInfoProcess(GetAllWindowsTree());
  51.        }
  52.  
  53.        /// <summary>
  54.        /// Gets all windows in nested objects usefule for adding to a TreeView.
  55.        /// Includes the extended information: caption, class, handle, parent,
  56.        /// children, and siblings. The list starts with the desktop.
  57.        /// </summary>
  58.        /// <returns>Desktop WindowInformation object with nested children</returns>
  59.        public static WindowInformation GetAllWindowsTree() {
  60.            WindowInformation desktopWindow = winInfoGet(GetDesktopWindow());
  61.            desktopWindow.ChildWindows = getChildWindowsInfo(desktopWindow);
  62.            return desktopWindow;
  63.        }
  64.  
  65.        #endregion
  66.  
  67.        #region Unmanaged Code References
  68.  
  69.        /// <summary>
  70.        /// Enumerates the child windows that belong to the specified parent
  71.        /// window by passing the handle to each child window, in turn, to an
  72.        /// application-defined callback function. EnumChildWindows continues
  73.        /// until the last child window is enumerated or the callback function
  74.        /// returns FALSE.
  75.        /// </summary>
  76.        /// <param name="window">A handle to the parent window whose child windows are to be enumerated. If this parameter is NULL, this function is equivalent to EnumWindows.</param>
  77.        /// <param name="callback">A pointer to an application-defined callback function.</param>
  78.        /// <param name="i">An application-defined value to be passed to the callback function.</param>
  79.        /// <returns>Return FALSE</returns>
  80.        [DllImport("user32")]
  81.        [return: MarshalAs(UnmanagedType.Bool)]
  82.        private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
  83.  
  84.        /// <summary>
  85.        /// Retrieves a handle to a window whose class name and window name match the specified strings.
  86.        /// The function searches child windows, beginning with the one following the specified child window.
  87.        /// This function does not perform a case-sensitive search.
  88.        /// </summary>
  89.        /// <param name="hwndParent">A handle to the parent window whose child windows are to be searched. If hwndParent is NULL, the function uses the desktop window as the parent window. The function searches among windows that are child windows of the desktop. If hwndParent is HWND_MESSAGE, the function searches all message-only windows.</param>
  90.        /// <param name="hwndChildAfter">A handle to a child window. The search begins with the next child window in the Z order. The child window must be a direct child window of hwndParent, not just a descendant window. If hwndChildAfter is NULL, the search begins with the first child window of hwndParent. Note that if both hwndParent and hwndChildAfter are NULL, the function searches all top-level and message-only windows.</param>
  91.        /// <param name="lpszClass">Optional: The class name or a class atom created by a previous call to the RegisterClass or RegisterClassEx function. The atom must be placed in the low-order word of lpszClass; the high-order word must be zero. If lpszClass is a string, it specifies the window class name. The class name can be any name registered with RegisterClass or RegisterClassEx, or any of the predefined control-class names, or it can be MAKEINTATOM(0x8000). In this latter case, 0x8000 is the atom for a menu class. For more information, see the Remarks section of this topic.</param>
  92.        /// <param name="lpszWindow">Optional: The window name (the window's title). If this parameter is NULL, all window names match.</param>
  93.        /// <returns></returns>
  94.        [DllImport("user32.dll", EntryPoint = "FindWindowEx", CharSet = CharSet.Auto)]
  95.        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
  96.  
  97.        /// <summary>
  98.        /// Retrieves the name of the class to which the specified window belongs.
  99.        /// </summary>
  100.        /// <param name="hWnd">A handle to the window and, indirectly, the class to which the window belongs.</param>
  101.        /// <param name="lpClassName">The class name string.</param>
  102.        /// <param name="nMaxCount">The length of the lpClassName buffer, in characters. The buffer must be large enough to include the terminating null character; otherwise, the class name string is truncated to nMaxCount-1 characters.</param>
  103.        /// <returns>If the function succeeds, the return value is the number of characters copied to the buffer, not including the terminating null character. If the function fails, the return value is zero. To get extended error information, call GetLastError.</returns>
  104.        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
  105.        private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
  106.  
  107.        /// <summary>
  108.        /// Retrieves a handle to the desktop window. The desktop window covers the entire screen. The
  109.        /// desktop window is the area on top of which other windows are painted.
  110.        /// </summary>
  111.        /// <returns>The return value is a handle to the desktop window</returns>
  112.        [DllImport("user32.dll", SetLastError = false)]
  113.        private static extern IntPtr GetDesktopWindow();        
  114.  
  115.        /// <summary>
  116.        /// Retrieves a handle to a window that has the specified relationship (Z-Order or owner) to
  117.        /// the specified window.
  118.        /// </summary>
  119.        /// <param name="hWnd">A handle to a window. The window handle retrieved is relative to this window, based on the value of the uCmd parameter.</param>
  120.        /// <param name="uCmd">The relationship between the specified window and the window whose handle is to be retrieved. This parameter can be one of the following values.</param>
  121.        /// <returns>If the function succeeds, the return value is a window handle. If no window exists with the specified relationship to the specified window, the return value is NULL. To get extended error information, call GetLastError.</returns>
  122.        [DllImport("user32.dll", SetLastError = true)]
  123.        private static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
  124.  
  125.        /// <summary>
  126.        /// Copies the text of the specified window's title bar (if it has one) into a buffer. If the
  127.        /// specified window is a control, the text of the control is copied. However, GetWindowText
  128.        /// cannot retrieve the text of a control in another application.
  129.        /// </summary>
  130.        /// <param name="hWnd">A handle to the window or control containing the text.</param>
  131.        /// <param name="text">The buffer that will receive the text. If the string is as long or longer than the buffer, the string is truncated and terminated with a null character.</param>
  132.        /// <param name="count">The maximum number of characters to copy to the buffer, including the null character. If the text exceeds this limit, it is truncated.</param>
  133.        /// <returns>If the function succeeds, the return value is the length, in characters, of the copied string, not including the terminating null character. If the window has no title bar or text, if the title bar is empty, or if the window or control handle is invalid, the return value is zero. To get extended error information, call GetLastError.</returns>      
  134.        [DllImport("user32.dll")]
  135.        private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
  136.  
  137.        /// <summary>
  138.        /// Sends the specified message to a window or windows. The SendMessage function calls the
  139.        /// window procedure for the specified window and does not return until the window procedure
  140.        /// has processed the message.
  141.        /// </summary>
  142.        /// <param name="hwnd">A handle to the window whose window procedure will receive the message. If this parameter is HWND_BROADCAST ((HWND)0xffff), the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.</param>
  143.        /// <param name="wmConstant">Messages defined in wmConstants enum. See pinvoke.net for more details.</param>
  144.        /// <param name="wParam">StringBuilder capacity.</param>
  145.        /// <param name="sb">StringBuilder object.</param>
  146.        /// <returns></returns>
  147.        [DllImport("User32.dll")]
  148.        private static extern int SendMessage(IntPtr hwnd, WMConstants wmConstant, int wParam, StringBuilder sb);
  149.  
  150.        /// <summary>
  151.        /// Sends the specified message to a window or windows. The SendMessage function calls the
  152.        /// window procedure for the specified window and does not return until the window procedure
  153.        /// has processed the message.
  154.        /// </summary>
  155.        /// <param name="hwnd">A handle to the window whose window procedure will receive the message. If this parameter is HWND_BROADCAST ((HWND)0xffff), the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.</param>
  156.        /// <param name="wmConstant">Messages defined in wmConstants enum. See pinvoke.net for more details.</param>
  157.        /// <param name="wParam">IntPtr.Zero</param>
  158.        /// <param name="lParam">IntPtr.Zero</param>
  159.        /// <returns></returns>
  160.        [DllImport("User32.dll")]
  161.        private static extern int SendMessage(IntPtr hwnd, WMConstants wmConstant, IntPtr wParam, IntPtr lParam);        
  162.  
  163.        #endregion
  164.  
  165.        #region Defnitions
  166.  
  167.        private delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
  168.  
  169.        private enum GetWindow_Cmd : uint {
  170.            GW_HWNDFIRST = 0,
  171.            GW_HWNDLAST = 1,
  172.            GW_HWNDNEXT = 2,
  173.            GW_HWNDPREV = 3,
  174.            GW_OWNER = 4,
  175.            GW_CHILD = 5,
  176.            GW_ENABLEDPOPUP = 6
  177.        }
  178.  
  179.        private enum WMConstants {            
  180.            WM_GETTEXT = 0x000D,
  181.            WM_GETTEXTLENGTH = 0x000E
  182.        }
  183.  
  184.        #endregion
  185.  
  186.        #region Static Methods
  187.  
  188.        /// <summary>
  189.        /// The delegate functions that is called by EnumChildWindows
  190.        /// </summary>
  191.        /// <param name="handle">Window handle</param>
  192.        /// <param name="pointer">Pointer to the IntPtr list.</param>
  193.        /// <returns>Boolean</returns>
  194.        private static bool enumWindow(IntPtr handle, IntPtr pointer) {
  195.            GCHandle gch = GCHandle.FromIntPtr(pointer);
  196.            List<IntPtr> list = gch.Target as List<IntPtr>;
  197.            if (list == null) {
  198.                throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
  199.            }
  200.            list.Add(handle);
  201.            return true;
  202.        }
  203.  
  204.        /// <summary>
  205.        /// Called by GetAllWindows.
  206.        /// </summary>
  207.        /// <param name="parent">The handle of the desktop window.</param>
  208.        /// <returns>List of window handles.</returns>
  209.        private static List<IntPtr> getChildWindows(IntPtr parent) {
  210.            List<IntPtr> result = new List<IntPtr>();
  211.            GCHandle listHandle = GCHandle.Alloc(result);
  212.            try {
  213.                EnumWindowProc childProc = new EnumWindowProc(enumWindow);
  214.                EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
  215.            } finally {
  216.                if (listHandle.IsAllocated)
  217.                    listHandle.Free();
  218.            }
  219.            return result;
  220.        }
  221.  
  222.        /// <summary>
  223.        /// Called by GeAlltWindowsTree and builds the nested WindowInformation
  224.        /// object with extended window information. Recursive function.
  225.        /// </summary>
  226.        /// <param name="parent">The parent window.</param>
  227.        /// <returns>List of WindowInformation objects.</returns>
  228.        private static List<WindowInformation> getChildWindowsInfo(WindowInformation parent) {
  229.            List<WindowInformation> result = new List<WindowInformation>();
  230.            IntPtr childHwnd = GetWindow(parent.Handle, GetWindow_Cmd.GW_CHILD);
  231.            while (childHwnd != IntPtr.Zero) {
  232.                WindowInformation child = winInfoGet(childHwnd);
  233.                child.Parent = parent;
  234.                child.ChildWindows = getChildWindowsInfo(child);
  235.                result.Add(child);
  236.                childHwnd = FindWindowEx(parent.Handle, childHwnd, null, null);
  237.            }
  238.            foreach (WindowInformation child in result) {
  239.                child.SiblingWindows.AddRange(result);
  240.                child.SiblingWindows.Remove(child);
  241.            }
  242.            return result;
  243.        }
  244.  
  245.        /// <summary>
  246.        /// Called by GetAllWindowsExtededInfo. Flattens the nested WindowInformation
  247.        /// object built by GetAllWindowsTree.
  248.        /// </summary>
  249.        /// <param name="winInfo">The nested WindowInformation object created by GetAllWindowsTree.</param>
  250.        /// <returns>Flattened list of WindowInformation objects with extended information.</returns>
  251.        private static List<WindowInformation> winInfoExtendedInfoProcess(WindowInformation winInfo) {
  252.            List<WindowInformation> winInfoList = new List<WindowInformation>();
  253.            winInfoList.Add(winInfo);
  254.            foreach (WindowInformation child in winInfo.ChildWindows) {
  255.                winInfoList.AddRange(winInfoExtendedInfoProcess(child));
  256.            }
  257.            return winInfoList;
  258.        }
  259.  
  260.        /// <summary>
  261.        /// Gets the basic window information from a handle.
  262.        /// </summary>
  263.        /// <param name="hWnd">Window handle.</param>
  264.        /// <returns>WindowInformation object with basic information.</returns>
  265.        private static WindowInformation winInfoGet(IntPtr hWnd) {
  266.            StringBuilder caption = new StringBuilder(1024);
  267.            StringBuilder className = new StringBuilder(1024);
  268.            GetWindowText(hWnd, caption, caption.Capacity);
  269.            GetClassName(hWnd, className, className.Capacity);
  270.            WindowInformation wi = new WindowInformation();
  271.            wi.Handle = hWnd;
  272.            wi.Class = className.ToString();
  273.            if (caption.ToString() != string.Empty) {
  274.                wi.Caption = caption.ToString();
  275.            } else {
  276.                caption = new StringBuilder(Convert.ToInt32(SendMessage(wi.Handle, WMConstants.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero)) + 1);
  277.                SendMessage(wi.Handle, WMConstants.WM_GETTEXT, caption.Capacity, caption);
  278.                wi.Caption = caption.ToString();
  279.            }            
  280.            return wi;
  281.        }        
  282.  
  283.        #endregion
  284.  
  285.    }
  286.  
  287.    /// <summary>
  288.    /// Object that holds window specific information.
  289.    /// </summary>
  290.    public class WindowInformation {
  291.  
  292.        #region Constructor
  293.  
  294.        /// <summary>
  295.        /// Initialize the class.
  296.        /// </summary>
  297.        public WindowInformation() { }
  298.  
  299.        #endregion
  300.  
  301.        #region Properties
  302.  
  303.        /// <summary>
  304.        /// The window caption.
  305.        /// </summary>
  306.        public string Caption = string.Empty;
  307.  
  308.        /// <summary>
  309.        /// The window class.
  310.        /// </summary>
  311.        public string Class = string.Empty;
  312.  
  313.        /// <summary>
  314.        /// Children of the window.
  315.        /// </summary>
  316.        public List<WindowInformation> ChildWindows = new List<WindowInformation>();
  317.  
  318.        /// <summary>
  319.        /// Unmanaged code to get the process and thres IDs of the window.
  320.        /// </summary>
  321.        /// <param name="hWnd"></param>
  322.        /// <param name="processId"></param>
  323.        /// <returns></returns>
  324.        [DllImport("user32")]
  325.        private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId);
  326.  
  327.        /// <summary>
  328.        /// The string representation of the window.
  329.        /// </summary>
  330.        /// <returns></returns>
  331.        public override string ToString() {
  332.            return "Window " + this.Handle.ToString() + " \"" + this.Caption + "\" " + this.Class;
  333.        }
  334.  
  335.        /// <summary>
  336.        /// The handles of the child windows.
  337.        /// </summary>
  338.        public List<IntPtr> ChildWindowHandles {
  339.            get {
  340.                try {
  341.                    var handles = from c in this.ChildWindows.AsEnumerable()
  342.                            select c.Handle;                            
  343.                    return handles.ToList<IntPtr>();
  344.                } catch (Exception ex) {
  345.                    return null;
  346.                }
  347.            }
  348.        }
  349.  
  350.        /// <summary>
  351.        /// The window handle.
  352.        /// </summary>
  353.        public IntPtr Handle;
  354.  
  355.        /// <summary>
  356.        /// The parent window.
  357.        /// </summary>
  358.        public WindowInformation Parent { get; set; }
  359.  
  360.        /// <summary>
  361.        /// The handle of the parent of the window.
  362.        /// </summary>
  363.        public IntPtr ParentHandle {
  364.            get {
  365.                if (this.Parent != null) return this.Parent.Handle;
  366.                else return IntPtr.Zero;
  367.            }
  368.        }
  369.  
  370.        /// <summary>
  371.        /// The corresponding process.
  372.        /// </summary>
  373.        public Process Process {
  374.            get {
  375.                try {
  376.                    int processID = 0;
  377.                    GetWindowThreadProcessId(this.Handle, out processID);
  378.                    return Process.GetProcessById(processID);
  379.                } catch (Exception ex) { return null; }
  380.            }
  381.        }
  382.  
  383.        /// <summary>
  384.        /// Sibling window information.
  385.        /// </summary>
  386.        public List<WindowInformation> SiblingWindows = new List<WindowInformation>();
  387.  
  388.        /// <summary>
  389.        /// The handles of the sibling windows.
  390.        /// </summary>
  391.        public List<IntPtr> SiblingWindowHandles {
  392.            get {
  393.                try {
  394.                    var handles = from s in this.SiblingWindows.AsEnumerable()
  395.                                  select s.Handle;
  396.                    return handles.ToList<IntPtr>();
  397.                } catch (Exception ex) {
  398.                    return null;
  399.                }
  400.            }
  401.        }
  402.  
  403.        /// <summary>
  404.        /// The thread ID of the window. Returns -1 on exception.
  405.        /// </summary>
  406.        public int ThreadID {
  407.            get {
  408.                try {
  409.                    int dummy = 0;
  410.                    return GetWindowThreadProcessId(this.Handle, out dummy);
  411.                } catch (Exception ex) { return -1; }
  412.            }
  413.        }
  414.  
  415.        [DllImport("user32")]
  416.        private static extern int SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
  417.        private const int WM_CLOSE = 0x10;
  418.  
  419.        // send WM_CLOSE to a window
  420.        public void Close() {
  421.            SendMessage(this.Handle, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
  422.        }
  423.  
  424.        #endregion
  425.    }
  426. }
  427. "@
  428.  
  429. # waiting on the user to log on so that WinSize2 becomes operational
  430. while ($true)
  431. {
  432.     $LogonUI = Get-Process | where { $_.name -eq "LogonUI" }
  433.     if (!$LogonUI) { break }
  434.     Start-Sleep -Milliseconds 50
  435. }
  436.  
  437. # starting chrome maximized and don't forget to make the chrome shortcut do the same, otherwise it won't always be maximized and WinSize2 fixes position and size of tabs outliner
  438. start chrome --start-maximized
  439.  
  440. while ($true)
  441. {
  442.     $TabsOutliner = Get-Process | where { $_.name -eq "chrome" -and $_.mainwindowtitle -eq "Tabs Outliner" }
  443.     if ($TabsOutliner) { break }
  444.     Start-Sleep -Milliseconds 50
  445. }
  446.  
  447. <# OLD CODE (won't work when another app runs at startup and takes the first place in the ALT+TAB window collection)
  448. # giving the main chrome window focus by doing ALT+TAB to switch back to the previous window
  449. $wsh = New-Object -ComObject Wscript.Shell
  450. $wsh.Sendkeys("%{TAB}")
  451.  
  452. while ($true)
  453. {
  454.     $NewTabChrome = Get-Process | where { $_.name -eq "chrome" -and $_.mainwindowtitle -eq "Nieuw tabblad - Google Chrome" }
  455.     if ($NewTabChrome) { break }
  456.     Start-Sleep -Milliseconds 50
  457. }
  458.  
  459. # this only works when this chrome window has focus (which it now should have)
  460. $NewTabChrome.CloseMainWindow() > $null
  461. #>
  462.  
  463. # closing the chrome main window (can be done in AHK with this simple one-liner: WinClose("Nieuw tabblad - Google Chrome"))
  464. $windows = [Win32.WindowList]::GetAllWindows()
  465. $newTabChrome = $windows | where { $_.class -eq "Chrome_WidgetWin_1" -and $_.caption -eq "Nieuw tabblad - Google Chrome" }
  466. $newTabChrome.Close()
  467.  
  468. <# if you don't want to minimize all windows; then get the handle that's saved in $newTabChrome and save it in $newTabChromeHandle, then the code below minimizes only that window
  469. Add-Type -name NativeMethods -namespace Win32 -MemberDefinition @'
  470. [DllImport("user32.dll")]
  471. public static extern bool CloseWindow(IntPtr hWnd);
  472. '@
  473.  
  474. [Win32.NativeMethods]::CloseWindow($newTabChromeHandle)
  475. #>
  476.  
  477. $x = New-Object -ComObject Shell.Application
  478. $x.minimizeall()
  479.  
  480. <# MinimizedTabsOutliner-wrapped.ps1.bat / README.md
  481. # Minimized Tabs Outliner (wrapped .ps1).bat
  482. IMPORTANT: the following title in the script must be made identical to the one that you see in the tiny preview window, when your cursor is on the chrome icon in the taskbar with the 'new tab' chrome window in view: `Nieuw tabblad - Google Chrome` (Dutch language).
  483.  
  484. The powershell wrapper/batch-powershell hybrid makes using the powershell script as easy as with any other executable file. Easily run the embedded powershell script by double-clicking the .bat file. It also makes it super easy when you create a shortcut of it, which I recommended you do to make it run minimized as well. Simply right-click the .bat file and then click on "Create shortcut". These actions won't work with non-wrapped .ps1 files and would've required a more difficult workflow, which isn't particularly straightforward for end users. After you have made the shortcut, you have to make it run at startup by pressing the `WinKey + R`, then copy and paste the following text into the **Run** dialog box: `shell:startup`. Then the startup folder will open in which the shortcut has to be placed. After this you're done.
  485.  
  486. You can also run the .bat file completely hidden at startup by using the following AutoHotKey script instead of a shortcut, and ofcourse placed in the startup folder (replace `XXX` with your Windows account name):
  487. ```
  488. #Requires AutoHotkey 2.0.5
  489. #NoTrayIcon
  490. Run "C:\Users\XXX\Documents\Minimized Tabs Outliner (wrapped .ps1).bat",,"Hide"
  491. ```
  492.  
  493. When you double-click a non-wrapped .ps1 file, it will open in notepad, the same thing happens when you create a shortcut of it like described before. To create a proper shortcut of a non-wrapped .ps1 file, you would have to open the shortcut wizard and include some text in front of the .ps1 file location, to run it with powershell when the shortcut gets double-clicked, and even more text to bypass the execution policy, so that it works on all devices.
  494. #>
Add Comment
Please, Sign In to add comment