mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Added cross-platform Get-Clipboard and Set-Clipboard (#10340)
Co-Authored-By: Ilya <darpa@yandex.ru> Co-Authored-By: Ilya <darpa@yandex.ru>
This commit is contained in:
committed by
Travis Plunk
co-authored by
Ilya
parent
4b8462766f
commit
b74a26bb91
+4
-3
@@ -1331,9 +1331,6 @@
|
||||
<Component Id="cmpB2DC1821DBE648078AEA75AC0AB62408" Guid="{4242bbb5-81dd-481d-a46a-6397d5bce4a5}">
|
||||
<File Id="filA7C18F70F1814A08A63620BC16B1C4DC" KeyPath="yes" Source="$(env.ProductSourcePath)\ref\System.IO.FileSystem.DriveInfo.dll" />
|
||||
</Component>
|
||||
<Component Id="cmpD63D95DCAE9747E3A170CDD082EE4432" Guid="{8fb8d745-02e0-4ca3-b570-06981423b367}">
|
||||
<File Id="filC57EEBC7B79642DF81737183462ABBE4" KeyPath="yes" Source="$(env.ProductSourcePath)\ref\System.Drawing.dll" />
|
||||
</Component>
|
||||
<Component Id="cmp9C1983722FB842AEAAE7FE004439F7F5" Guid="{28fac38a-2d64-4651-b17d-822f689ad00f}">
|
||||
<File Id="fil3E3F9C4BC1D5493798264C5592B2D26B" KeyPath="yes" Source="$(env.ProductSourcePath)\ref\System.Security.Principal.dll" />
|
||||
</Component>
|
||||
@@ -1643,6 +1640,9 @@
|
||||
<Component Id="cmpF1B0E6DCC3BD4797B206C879EF270062" Guid="{af38a3e7-6bc2-47c8-a83e-ee8bfd0cc8be}">
|
||||
<File Id="fil2694AE6F8EB8473CBDF0F73A4E55164B" KeyPath="yes" Source="$(env.ProductSourcePath)\ref\System.Text.Encoding.CodePages.dll" />
|
||||
</Component>
|
||||
<Component Id="cmp25A144CC34E545378735B06794A02F90" Guid="{35a3c141-1309-4277-9325-a97e177a9f09}">
|
||||
<File Id="filFCE4A935DE1D4DD08E9A1D32A07E0266" KeyPath="yes" Source="$(env.ProductSourcePath)\ref\System.Drawing.dll" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<Directory Id="dirC72EEAF9434D4AD066E0F4D20D8E816C" Name="en-US">
|
||||
<Component Id="cmpDC2EF4541FA5A2E63F36A8CD6C5FA51B" Guid="{CE8DDB7C-A16E-4A1E-80D5-9937D07A1723}">
|
||||
@@ -3919,6 +3919,7 @@
|
||||
<ComponentRef Id="cmp73A4CC8E2C9E4594A3D8258C9E00D7E6" />
|
||||
<ComponentRef Id="cmpAC984FA3A67247BC996F60290C87D0A1" />
|
||||
<ComponentRef Id="cmp2E32A6E773F543F0A150B972F8D3E23A" />
|
||||
<ComponentRef Id="cmp25A144CC34E545378735B06794A02F90" />
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
||||
|
||||
-4
@@ -18,14 +18,12 @@
|
||||
<Compile Remove="commands\management\ControlPanelItemCommand.cs" />
|
||||
<Compile Remove="commands\management\CommitTransactionCommand.cs" />
|
||||
<Compile Remove="commands\management\Eventlog.cs" />
|
||||
<Compile Remove="commands\management\GetClipboardCommand.cs" />
|
||||
<Compile Remove="commands\management\GetTransactionCommand.cs" />
|
||||
<Compile Remove="commands\management\GetWMIObjectCommand.cs" />
|
||||
<Compile Remove="commands\management\InvokeWMIMethodCommand.cs" />
|
||||
<Compile Remove="commands\management\RegisterWMIEventCommand.cs" />
|
||||
<Compile Remove="commands\management\RemoveWMIObjectCommand.cs" />
|
||||
<Compile Remove="commands\management\RollbackTransactionCommand.cs" />
|
||||
<Compile Remove="commands\management\SetClipboardCommand.cs" />
|
||||
<Compile Remove="commands\management\SetWMIInstanceCommand.cs" />
|
||||
<Compile Remove="commands\management\StartTransactionCommand.cs" />
|
||||
<Compile Remove="commands\management\UseTransactionCommand.cs" />
|
||||
@@ -38,7 +36,6 @@
|
||||
<Compile Remove="gen\ControlPanelResources.cs" />
|
||||
<Compile Remove="gen\WmiResources.cs" />
|
||||
<Compile Remove="gen\ManagementMshSnapInResources.cs" />
|
||||
<Compile Remove="gen\ClipboardResources.cs" />
|
||||
|
||||
<EmbeddedResource Remove="resources\EventlogResources.resx" />
|
||||
<EmbeddedResource Remove="resources\TransactionResources.resx" />
|
||||
@@ -46,7 +43,6 @@
|
||||
<EmbeddedResource Remove="resources\ControlPanelResources.resx" />
|
||||
<EmbeddedResource Remove="resources\WmiResources.resx" />
|
||||
<EmbeddedResource Remove="resources\ManagementMshSnapInResources.resx" />
|
||||
<EmbeddedResource Remove="resources\ClipboardResources.resx" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.PowerShell.Commands.Internal
|
||||
{
|
||||
internal static class Clipboard
|
||||
{
|
||||
private static bool? _clipboardSupported;
|
||||
|
||||
// Used if an external clipboard is not available, e.g. if xclip is missing.
|
||||
// This is useful for testing in CI as well.
|
||||
private static string _internalClipboard;
|
||||
|
||||
private static string StartProcess(
|
||||
string tool,
|
||||
string args,
|
||||
string stdin = "" )
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo();
|
||||
startInfo.UseShellExecute = false;
|
||||
startInfo.RedirectStandardInput = true;
|
||||
startInfo.RedirectStandardOutput = true;
|
||||
startInfo.RedirectStandardError = true;
|
||||
startInfo.FileName = tool;
|
||||
startInfo.Arguments = args;
|
||||
string stdout;
|
||||
|
||||
using (Process process = new Process())
|
||||
{
|
||||
process.StartInfo = startInfo;
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
}
|
||||
catch (System.ComponentModel.Win32Exception)
|
||||
{
|
||||
_clipboardSupported = false;
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(stdin))
|
||||
{
|
||||
process.StandardInput.Write(stdin);
|
||||
process.StandardInput.Close();
|
||||
}
|
||||
|
||||
stdout = process.StandardOutput.ReadToEnd();
|
||||
process.WaitForExit(250);
|
||||
|
||||
_clipboardSupported = process.ExitCode == 0;
|
||||
}
|
||||
|
||||
return stdout;
|
||||
}
|
||||
|
||||
public static string GetText()
|
||||
{
|
||||
if (_clipboardSupported == false)
|
||||
{
|
||||
return _internalClipboard ?? string.Empty;
|
||||
}
|
||||
|
||||
string tool = string.Empty;
|
||||
string args = string.Empty;
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
string clipboardText = string.Empty;
|
||||
ExecuteOnStaThread(() => GetTextImpl(out clipboardText));
|
||||
return clipboardText;
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
tool = "xclip";
|
||||
args = "-selection clipboard -out";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
tool = "pbpaste";
|
||||
}
|
||||
else
|
||||
{
|
||||
_clipboardSupported = false;
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return StartProcess(tool, args);
|
||||
}
|
||||
|
||||
public static void SetText(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_clipboardSupported == false)
|
||||
{
|
||||
_internalClipboard = text;
|
||||
return;
|
||||
}
|
||||
|
||||
string tool = string.Empty;
|
||||
string args = string.Empty;
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
ExecuteOnStaThread(() => SetClipboardData(Tuple.Create(text, CF_UNICODETEXT)));
|
||||
return;
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
tool = "xclip";
|
||||
args = "-selection clipboard -in";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
tool = "pbcopy";
|
||||
}
|
||||
else
|
||||
{
|
||||
_clipboardSupported = false;
|
||||
return;
|
||||
}
|
||||
|
||||
StartProcess(tool, args, text);
|
||||
if (_clipboardSupported == false)
|
||||
{
|
||||
_internalClipboard = text;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetRtf(string plainText, string rtfText)
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_CF_RTF == 0)
|
||||
{
|
||||
s_CF_RTF = RegisterClipboardFormat("Rich Text Format");
|
||||
}
|
||||
|
||||
ExecuteOnStaThread(() => SetClipboardData(
|
||||
Tuple.Create(plainText, CF_UNICODETEXT),
|
||||
Tuple.Create(rtfText, s_CF_RTF)));
|
||||
}
|
||||
|
||||
private const uint GMEM_MOVEABLE = 0x0002;
|
||||
private const uint GMEM_ZEROINIT = 0x0040;
|
||||
private const uint GHND = GMEM_MOVEABLE | GMEM_ZEROINIT;
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr GlobalAlloc(uint flags, UIntPtr dwBytes);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr GlobalFree(IntPtr hMem);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr GlobalLock(IntPtr hMem);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool GlobalUnlock(IntPtr hMem);
|
||||
|
||||
[DllImport("kernel32.dll", ExactSpelling = true, EntryPoint = "RtlMoveMemory", SetLastError = true)]
|
||||
private static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = false)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool IsClipboardFormatAvailable(uint format);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool OpenClipboard(IntPtr hWndNewOwner);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool CloseClipboard();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool EmptyClipboard();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern IntPtr GetClipboardData(uint format);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr SetClipboardData(uint format, IntPtr data);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern uint RegisterClipboardFormat(string lpszFormat);
|
||||
|
||||
private const uint CF_TEXT = 1;
|
||||
private const uint CF_UNICODETEXT = 13;
|
||||
private static uint s_CF_RTF;
|
||||
|
||||
private static bool GetTextImpl(out string text)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsClipboardFormatAvailable(CF_UNICODETEXT))
|
||||
{
|
||||
if (OpenClipboard(IntPtr.Zero))
|
||||
{
|
||||
var data = GetClipboardData(CF_UNICODETEXT);
|
||||
if (data != IntPtr.Zero)
|
||||
{
|
||||
data = GlobalLock(data);
|
||||
text = Marshal.PtrToStringUni(data);
|
||||
GlobalUnlock(data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsClipboardFormatAvailable(CF_TEXT))
|
||||
{
|
||||
if (OpenClipboard(IntPtr.Zero))
|
||||
{
|
||||
var data = GetClipboardData(CF_TEXT);
|
||||
if (data != IntPtr.Zero)
|
||||
{
|
||||
data = GlobalLock(data);
|
||||
text = Marshal.PtrToStringAnsi(data);
|
||||
GlobalUnlock(data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore exceptions
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
text = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool SetClipboardData(params Tuple<string, uint>[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!OpenClipboard(IntPtr.Zero))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
EmptyClipboard();
|
||||
|
||||
foreach (var d in data)
|
||||
{
|
||||
if (!SetSingleClipboardData(d.Item1, d.Item2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool SetSingleClipboardData(string text, uint format)
|
||||
{
|
||||
IntPtr hGlobal = IntPtr.Zero;
|
||||
IntPtr data = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
uint bytes;
|
||||
if (format == s_CF_RTF || format == CF_TEXT)
|
||||
{
|
||||
bytes = (uint)(text.Length + 1);
|
||||
data = Marshal.StringToHGlobalAnsi(text);
|
||||
}
|
||||
else if (format == CF_UNICODETEXT)
|
||||
{
|
||||
bytes = (uint)((text.Length + 1) * 2);
|
||||
data = Marshal.StringToHGlobalUni(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not yet supported format.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data == IntPtr.Zero)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
hGlobal = GlobalAlloc(GHND, (UIntPtr)bytes);
|
||||
if (hGlobal == IntPtr.Zero)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IntPtr dataCopy = GlobalLock(hGlobal);
|
||||
if (dataCopy == IntPtr.Zero)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CopyMemory(dataCopy, data, bytes);
|
||||
GlobalUnlock(hGlobal);
|
||||
|
||||
if (SetClipboardData(format, hGlobal) != IntPtr.Zero)
|
||||
{
|
||||
// The clipboard owns this memory now, so don't free it.
|
||||
hGlobal = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore failures
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (data != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(data);
|
||||
}
|
||||
|
||||
if (hGlobal != IntPtr.Zero)
|
||||
{
|
||||
GlobalFree(hGlobal);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void ExecuteOnStaThread(Func<bool> action)
|
||||
{
|
||||
const int RetryCount = 5;
|
||||
int tries = 0;
|
||||
|
||||
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
|
||||
{
|
||||
while (tries++ < RetryCount && !action())
|
||||
{
|
||||
// wait until RetryCount or action
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Exception exception = null;
|
||||
var thread = new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
while (tries++ < RetryCount && !action())
|
||||
{
|
||||
// wait until RetryCount or action
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
exception = e;
|
||||
}
|
||||
});
|
||||
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
thread.Join();
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
-154
@@ -3,72 +3,20 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Media;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.PowerShell.Commands.Internal;
|
||||
|
||||
namespace Microsoft.PowerShell.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the different type supported by the clipboard.
|
||||
/// </summary>
|
||||
public enum ClipboardFormat
|
||||
{
|
||||
/// Text format as default.
|
||||
Text = 0,
|
||||
|
||||
/// File format.
|
||||
FileDropList = 1,
|
||||
|
||||
/// Image format.
|
||||
Image = 2,
|
||||
|
||||
/// Audio format.
|
||||
Audio = 3,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Defines the implementation of the 'Get-Clipboard' cmdlet.
|
||||
/// This cmdlet get the content from system clipboard.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "Clipboard", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=526219")]
|
||||
[Cmdlet(VerbsCommon.Get, "Clipboard", HelpUri = "https://go.microsoft.com/fwlink/?LinkId=2109905")]
|
||||
[Alias("gcb")]
|
||||
[OutputType(typeof(string), typeof(FileInfo), typeof(Image), typeof(Stream))]
|
||||
[OutputType(typeof(string))]
|
||||
public class GetClipboardCommand : PSCmdlet
|
||||
{
|
||||
/// <summary>
|
||||
/// Property that sets clipboard type. This will return the required format from clipboard.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public ClipboardFormat Format { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Property that sets format type when the return type is text.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public TextDataFormat TextFormatType
|
||||
{
|
||||
get { return _textFormat; }
|
||||
|
||||
set
|
||||
{
|
||||
_isTextFormatTypeSet = true;
|
||||
_textFormat = value;
|
||||
}
|
||||
}
|
||||
|
||||
private TextDataFormat _textFormat = TextDataFormat.UnicodeText;
|
||||
private bool _isTextFormatTypeSet = false;
|
||||
|
||||
/// <summary>
|
||||
/// Property that sets raw parameter. This will allow clipboard return text or file list as one string.
|
||||
/// </summary>
|
||||
@@ -79,76 +27,38 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
set
|
||||
{
|
||||
_isRawSet = true;
|
||||
_raw = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _raw;
|
||||
private bool _isRawSet = false;
|
||||
|
||||
/// <summary>
|
||||
/// This method implements the ProcessRecord method for Get-Clipboard command.
|
||||
/// </summary>
|
||||
protected override void BeginProcessing()
|
||||
{
|
||||
// TextFormatType should only combine with Text.
|
||||
if (Format != ClipboardFormat.Text && _isTextFormatTypeSet)
|
||||
{
|
||||
ThrowTerminatingError(new ErrorRecord(new InvalidOperationException(
|
||||
string.Format(CultureInfo.InvariantCulture, ClipboardResources.InvalidTypeCombine)),
|
||||
"FailedToGetClipboard", ErrorCategory.InvalidOperation, "Clipboard"));
|
||||
}
|
||||
|
||||
// Raw should only combine with Text or FileDropList.
|
||||
if (Format != ClipboardFormat.Text && Format != ClipboardFormat.FileDropList && _isRawSet)
|
||||
{
|
||||
ThrowTerminatingError(new ErrorRecord(new InvalidOperationException(
|
||||
string.Format(CultureInfo.InvariantCulture, ClipboardResources.InvalidRawCombine)),
|
||||
"FailedToGetClipboard", ErrorCategory.InvalidOperation, "Clipboard"));
|
||||
}
|
||||
|
||||
if (Format == ClipboardFormat.Text)
|
||||
{
|
||||
this.WriteObject(GetClipboardContentAsText(_textFormat), true);
|
||||
}
|
||||
else if (Format == ClipboardFormat.Image)
|
||||
{
|
||||
this.WriteObject(Clipboard.GetImage());
|
||||
}
|
||||
else if (Format == ClipboardFormat.FileDropList)
|
||||
{
|
||||
if (_raw)
|
||||
{
|
||||
this.WriteObject(Clipboard.GetFileDropList(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.WriteObject(GetClipboardContentAsFileList());
|
||||
}
|
||||
}
|
||||
else if (Format == ClipboardFormat.Audio)
|
||||
{
|
||||
this.WriteObject(Clipboard.GetAudioStream());
|
||||
}
|
||||
this.WriteObject(GetClipboardContentAsText(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the clipboard content as text format.
|
||||
/// </summary>
|
||||
/// <param name="textFormat"></param>
|
||||
/// <returns></returns>
|
||||
private List<string> GetClipboardContentAsText(TextDataFormat textFormat)
|
||||
/// <returns>Array of strings representing content from clipboard.</returns>
|
||||
private List<string> GetClipboardContentAsText()
|
||||
{
|
||||
if (!Clipboard.ContainsText(textFormat))
|
||||
var result = new List<string>();
|
||||
string textContent = null;
|
||||
|
||||
try
|
||||
{
|
||||
return null;
|
||||
textContent = Clipboard.GetText();
|
||||
}
|
||||
catch (PlatformNotSupportedException)
|
||||
{
|
||||
ThrowTerminatingError(new ErrorRecord(new InvalidOperationException(ClipboardResources.UnsupportedPlatform), "FailedToGetClipboardUnsupportedPlatform", ErrorCategory.InvalidOperation, "Clipboard"));
|
||||
}
|
||||
|
||||
List<string> result = new List<string>();
|
||||
|
||||
// TextFormat default value is Text, by default it is same as Clipboard.GetText()
|
||||
string textContent = Clipboard.GetText(textFormat);
|
||||
if (_raw)
|
||||
{
|
||||
result.Add(textContent);
|
||||
@@ -161,54 +71,5 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the clipboard content as file info.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private List<PSObject> GetClipboardContentAsFileList()
|
||||
{
|
||||
if (!Clipboard.ContainsFileDropList())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<PSObject> result = new List<PSObject>();
|
||||
foreach (string filePath in Clipboard.GetFileDropList())
|
||||
{
|
||||
FileInfo file = new FileInfo(filePath);
|
||||
result.Add(WrapOutputInPSObject(file, filePath));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps the item in a PSObject and attaches some notes to the
|
||||
/// object that deal with path information.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
private PSObject WrapOutputInPSObject(
|
||||
FileInfo item,
|
||||
string path)
|
||||
{
|
||||
PSObject result = new PSObject(item);
|
||||
|
||||
// Now get the parent path and child name
|
||||
if (path != null)
|
||||
{
|
||||
// Get the parent path
|
||||
string parentPath = Directory.GetParent(path).FullName;
|
||||
result.AddOrSetProperty("PSParentPath", parentPath);
|
||||
|
||||
// Get the child name
|
||||
string childName = item.Name;
|
||||
result.AddOrSetProperty("PSChildName", childName);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-314
@@ -3,17 +3,11 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.PowerShell.Commands.Internal;
|
||||
|
||||
namespace Microsoft.PowerShell.Commands
|
||||
{
|
||||
@@ -21,20 +15,17 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// Defines the implementation of the 'Set-Clipboard' cmdlet.
|
||||
/// This cmdlet gets the content from system clipboard.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Set, "Clipboard", DefaultParameterSetName = "String", SupportsShouldProcess = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkId=526220")]
|
||||
[Cmdlet(VerbsCommon.Set, "Clipboard", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Medium, HelpUri = "https://go.microsoft.com/fwlink/?LinkId=2109826")]
|
||||
[Alias("scb")]
|
||||
public class SetClipboardCommand : PSCmdlet
|
||||
{
|
||||
private List<string> _contentList = new List<string>();
|
||||
private const string ValueParameterSet = "Value";
|
||||
private const string PathParameterSet = "Path";
|
||||
private const string LiteralPathParameterSet = "LiteralPath";
|
||||
|
||||
/// <summary>
|
||||
/// Property that sets clipboard content.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = ValueParameterSet, Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
[AllowNull]
|
||||
[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
|
||||
[System.Management.Automation.AllowNull]
|
||||
[AllowEmptyCollection]
|
||||
[AllowEmptyString]
|
||||
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
@@ -46,41 +37,6 @@ namespace Microsoft.PowerShell.Commands
|
||||
[Parameter]
|
||||
public SwitchParameter Append { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Property that sets Path parameter. This will allow to set file formats to Clipboard.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = PathParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[ValidateNotNullOrEmpty]
|
||||
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public string[] Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Property that sets LiteralPath parameter. This will allow to set file formats to Clipboard.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = LiteralPathParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true)]
|
||||
[Alias("PSPath")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
|
||||
public string[] LiteralPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Property that sets html parameter. This will allow html content rendered as html to clipboard.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public SwitchParameter AsHtml
|
||||
{
|
||||
get { return _asHtml; }
|
||||
|
||||
set
|
||||
{
|
||||
_isHtmlSet = true;
|
||||
_asHtml = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _asHtml;
|
||||
private bool _isHtmlSet = false;
|
||||
|
||||
/// <summary>
|
||||
/// This method implements the BeginProcessing method for Set-Clipboard command.
|
||||
/// </summary>
|
||||
@@ -94,26 +50,10 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
// Html should only combine with Text content.
|
||||
if (Value == null && _isHtmlSet)
|
||||
{
|
||||
ThrowTerminatingError(new ErrorRecord(new InvalidOperationException(
|
||||
string.Format(CultureInfo.InvariantCulture, ClipboardResources.InvalidHtmlCombine)),
|
||||
"FailedToSetClipboard", ErrorCategory.InvalidOperation, "Clipboard"));
|
||||
}
|
||||
|
||||
if (Value != null)
|
||||
{
|
||||
_contentList.AddRange(Value);
|
||||
}
|
||||
else if (Path != null)
|
||||
{
|
||||
_contentList.AddRange(Path);
|
||||
}
|
||||
else if (LiteralPath != null)
|
||||
{
|
||||
_contentList.AddRange(LiteralPath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -121,27 +61,15 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
protected override void EndProcessing()
|
||||
{
|
||||
if (LiteralPath != null)
|
||||
{
|
||||
CopyFilesToClipboard(_contentList, Append, true);
|
||||
}
|
||||
else if (Path != null)
|
||||
{
|
||||
CopyFilesToClipboard(_contentList, Append, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetClipboardContent(_contentList, Append, _asHtml);
|
||||
}
|
||||
SetClipboardContent(_contentList, Append);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the clipboard content.
|
||||
/// </summary>
|
||||
/// <param name="contentList"></param>
|
||||
/// <param name="append"></param>
|
||||
/// <param name="asHtml"></param>
|
||||
private void SetClipboardContent(List<string> contentList, bool append, bool asHtml)
|
||||
/// <param name="contentList">The content to store into the clipboard.</param>
|
||||
/// <param name="append">If true, appends to clipboard instead of overwriting.</param>
|
||||
private void SetClipboardContent(List<string> contentList, bool append)
|
||||
{
|
||||
string setClipboardShouldProcessTarget;
|
||||
|
||||
@@ -150,7 +78,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.ClipboardCleared);
|
||||
if (ShouldProcess(setClipboardShouldProcessTarget, "Set-Clipboard"))
|
||||
{
|
||||
Clipboard.Clear();
|
||||
Clipboard.SetText(string.Empty);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -159,15 +87,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
StringBuilder content = new StringBuilder();
|
||||
if (append)
|
||||
{
|
||||
if (!Clipboard.ContainsText())
|
||||
{
|
||||
WriteVerbose(string.Format(CultureInfo.InvariantCulture, ClipboardResources.NoAppendableClipboardContent));
|
||||
append = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
content.AppendLine(Clipboard.GetText());
|
||||
}
|
||||
content.AppendLine(Clipboard.GetText());
|
||||
}
|
||||
|
||||
if (contentList != null)
|
||||
@@ -175,7 +95,6 @@ namespace Microsoft.PowerShell.Commands
|
||||
content.Append(string.Join(Environment.NewLine, contentList.ToArray(), 0, contentList.Count));
|
||||
}
|
||||
|
||||
// Verbose output
|
||||
string verboseString = null;
|
||||
if (contentList != null)
|
||||
{
|
||||
@@ -198,230 +117,8 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
if (ShouldProcess(setClipboardShouldProcessTarget, "Set-Clipboard"))
|
||||
{
|
||||
// Set the text data
|
||||
Clipboard.Clear();
|
||||
if (asHtml)
|
||||
Clipboard.SetText(GetHtmlDataString(content.ToString()), TextDataFormat.Html);
|
||||
else
|
||||
Clipboard.SetText(content.ToString());
|
||||
Clipboard.SetText(content.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy the file format to clipboard.
|
||||
/// </summary>
|
||||
/// <param name="fileList"></param>
|
||||
/// <param name="append"></param>
|
||||
/// <param name="isLiteralPath"></param>
|
||||
private void CopyFilesToClipboard(List<string> fileList, bool append, bool isLiteralPath)
|
||||
{
|
||||
int clipBoardContentLength = 0;
|
||||
HashSet<string> dropFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// Append the new file list after the file list exists in the clipboard.
|
||||
if (append)
|
||||
{
|
||||
if (!Clipboard.ContainsFileDropList())
|
||||
{
|
||||
WriteVerbose(string.Format(CultureInfo.InvariantCulture, ClipboardResources.NoAppendableClipboardContent));
|
||||
append = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
StringCollection clipBoardContent = Clipboard.GetFileDropList();
|
||||
dropFiles = new HashSet<string>(clipBoardContent.Cast<string>().ToList(), StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// we need the count of original files so we can get the accurate files number that has been appended.
|
||||
clipBoardContentLength = clipBoardContent.Count;
|
||||
}
|
||||
}
|
||||
|
||||
ProviderInfo provider = null;
|
||||
for (int i = 0; i < fileList.Count; i++)
|
||||
{
|
||||
Collection<string> newPaths = new Collection<string>();
|
||||
|
||||
try
|
||||
{
|
||||
if (isLiteralPath)
|
||||
{
|
||||
newPaths.Add(Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(fileList[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
newPaths = Context.SessionState.Path.GetResolvedProviderPathFromPSPath(fileList[i], out provider);
|
||||
}
|
||||
}
|
||||
catch (ItemNotFoundException exception)
|
||||
{
|
||||
WriteError(new ErrorRecord(exception, "FailedToSetClipboard", ErrorCategory.InvalidOperation, "Clipboard"));
|
||||
}
|
||||
|
||||
foreach (string fileName in newPaths)
|
||||
{
|
||||
// Avoid adding duplicated files.
|
||||
if (!dropFiles.Contains(fileName))
|
||||
{
|
||||
dropFiles.Add(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dropFiles.Count == 0)
|
||||
return;
|
||||
|
||||
// Verbose output
|
||||
string setClipboardShouldProcessTarget;
|
||||
if ((dropFiles.Count - clipBoardContentLength) == 1)
|
||||
{
|
||||
if (append)
|
||||
{
|
||||
setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.AppendSingleFileToClipboard, dropFiles.ElementAt<string>(dropFiles.Count - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.SetSingleFileToClipboard, dropFiles.ElementAt<string>(0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (append)
|
||||
{
|
||||
setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.AppendMultipleFilesToClipboard, (dropFiles.Count - clipBoardContentLength));
|
||||
}
|
||||
else
|
||||
{
|
||||
setClipboardShouldProcessTarget = string.Format(CultureInfo.InvariantCulture, ClipboardResources.SetMultipleFilesToClipboard, dropFiles.Count);
|
||||
}
|
||||
}
|
||||
|
||||
if (ShouldProcess(setClipboardShouldProcessTarget, "Set-Clipboard"))
|
||||
{
|
||||
// Set file list formats to clipboard.
|
||||
Clipboard.Clear();
|
||||
StringCollection fileDropList = new StringCollection();
|
||||
fileDropList.AddRange(dropFiles.ToArray());
|
||||
Clipboard.SetFileDropList(fileDropList);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate HTML fragment data string with header that is required for the clipboard.
|
||||
/// </summary>
|
||||
/// <param name="html">The html to generate for.</param>
|
||||
/// <returns>The resulted string.</returns>
|
||||
private static string GetHtmlDataString(string html)
|
||||
{
|
||||
// The string contains index references to other spots in the string, so we need placeholders so we can compute the offsets.
|
||||
// The "<<<<<<<<1,<<<<<<<<2, etc" strings are just placeholders. We'll back-patch them actual values within the header location afterwards.
|
||||
const string Header = @"Version:0.9
|
||||
StartHTML:<<<<<<<<1
|
||||
EndHTML:<<<<<<<<2
|
||||
StartFragment:<<<<<<<<3
|
||||
EndFragment:<<<<<<<<4
|
||||
StartSelection:<<<<<<<<3
|
||||
EndSelection:<<<<<<<<4";
|
||||
|
||||
const string StartFragment = "<!--StartFragment-->";
|
||||
const string EndFragment = @"<!--EndFragment-->";
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(Header);
|
||||
sb.AppendLine(@"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.0 Transitional//EN"">");
|
||||
|
||||
// if given html already provided the fragments we won't add them
|
||||
int fragmentStart, fragmentEnd;
|
||||
int fragmentStartIdx = html.IndexOf(StartFragment, StringComparison.OrdinalIgnoreCase);
|
||||
int fragmentEndIdx = html.LastIndexOf(EndFragment, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// if html tag is missing add it surrounding the given html
|
||||
// find the index of "<html", ignore white space and case
|
||||
int htmlOpenIdx = Regex.Match(html, @"<\s*h\s*t\s*m\s*l", RegexOptions.IgnoreCase).Index;
|
||||
int htmlOpenEndIdx = htmlOpenIdx > 0 ? html.IndexOf('>', htmlOpenIdx) + 1 : -1;
|
||||
// find the index of "</html", ignore white space and case
|
||||
int htmlCloseIdx = Regex.Match(html, @"<\s*/\s*h\s*t\s*m\s*l", RegexOptions.IgnoreCase).Index;
|
||||
|
||||
if (fragmentStartIdx < 0 && fragmentEndIdx < 0)
|
||||
{
|
||||
// find the index of "<body", ignore white space and case
|
||||
int bodyOpenIdx = Regex.Match(html, @"<\s*b\s*o\s*d\s*y", RegexOptions.IgnoreCase).Index;
|
||||
int bodyOpenEndIdx = bodyOpenIdx > 0 ? html.IndexOf('>', bodyOpenIdx) + 1 : -1;
|
||||
|
||||
if (htmlOpenEndIdx < 0 && bodyOpenEndIdx < 0)
|
||||
{
|
||||
// the given html doesn't contain html or body tags so we need to add them and place start/end fragments around the given html only
|
||||
sb.Append("<html><body>");
|
||||
sb.Append(StartFragment);
|
||||
fragmentStart = GetByteCount(sb);
|
||||
sb.Append(html);
|
||||
fragmentEnd = GetByteCount(sb);
|
||||
sb.Append(EndFragment);
|
||||
sb.Append("</body></html>");
|
||||
}
|
||||
else
|
||||
{
|
||||
// insert start/end fragments in the proper place (related to html/body tags if exists) so the paste will work correctly
|
||||
// find the index of "</body", ignore white space and case
|
||||
int bodyCloseIdx = Regex.Match(html, @"<\s*/\s*b\s*o\s*d\s*y", RegexOptions.IgnoreCase).Index;
|
||||
|
||||
if (htmlOpenEndIdx < 0)
|
||||
sb.Append("<html>");
|
||||
else
|
||||
sb.Append(html, 0, htmlOpenEndIdx);
|
||||
|
||||
if (bodyOpenEndIdx > -1)
|
||||
sb.Append(html, htmlOpenEndIdx > -1 ? htmlOpenEndIdx : 0, bodyOpenEndIdx - (htmlOpenEndIdx > -1 ? htmlOpenEndIdx : 0));
|
||||
|
||||
sb.Append(StartFragment);
|
||||
fragmentStart = GetByteCount(sb);
|
||||
|
||||
var innerHtmlStart = bodyOpenEndIdx > -1 ? bodyOpenEndIdx : (htmlOpenEndIdx > -1 ? htmlOpenEndIdx : 0);
|
||||
var innerHtmlEnd = bodyCloseIdx > 0 ? bodyCloseIdx : (htmlCloseIdx > 0 ? htmlCloseIdx : html.Length);
|
||||
sb.Append(html, innerHtmlStart, innerHtmlEnd - innerHtmlStart);
|
||||
|
||||
fragmentEnd = GetByteCount(sb);
|
||||
sb.Append(EndFragment);
|
||||
|
||||
if (innerHtmlEnd < html.Length)
|
||||
sb.Append(html, innerHtmlEnd, html.Length - innerHtmlEnd);
|
||||
|
||||
if (htmlCloseIdx <= 0)
|
||||
sb.Append("</html>");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// directly return the cf_html
|
||||
return html;
|
||||
}
|
||||
|
||||
// Back-patch offsets, the replace text area is restricted to header only from index 0 to header.Length
|
||||
sb.Replace("<<<<<<<<1", Header.Length.ToString("D9", CultureInfo.CreateSpecificCulture("en-US")), 0, Header.Length);
|
||||
sb.Replace("<<<<<<<<2", GetByteCount(sb).ToString("D9", CultureInfo.CreateSpecificCulture("en-US")), 0, Header.Length);
|
||||
sb.Replace("<<<<<<<<3", fragmentStart.ToString("D9", CultureInfo.CreateSpecificCulture("en-US")), 0, Header.Length);
|
||||
sb.Replace("<<<<<<<<4", fragmentEnd.ToString("D9", CultureInfo.CreateSpecificCulture("en-US")), 0, Header.Length);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the number of bytes produced by encoding the string in the string builder in UTF-8 and not .NET default string encoding.
|
||||
/// </summary>
|
||||
/// <param name="sb">The string builder to count its string.</param>
|
||||
/// <param name="start">Optional: the start index to calculate from (default - start of string).</param>
|
||||
/// <param name="end">Optional: the end index to calculate to (default - end of string).</param>
|
||||
/// <returns>The number of bytes required to encode the string in UTF-8.</returns>
|
||||
private static int GetByteCount(StringBuilder sb, int start = 0, int end = -1)
|
||||
{
|
||||
char[] _byteCount = new char[1];
|
||||
int count = 0;
|
||||
end = end > -1 ? end : sb.Length;
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
_byteCount[0] = sb[i];
|
||||
count += Encoding.UTF8.GetByteCount(_byteCount);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,4 +131,22 @@
|
||||
<data name="InvalidHtmlCombine" xml:space="preserve">
|
||||
<value>Html can only be combined with Html Text format.</value>
|
||||
</data>
|
||||
<data name="UnsupportedFormat" xml:space="preserve">
|
||||
<value>Only Text format is supported on this platform.</value>
|
||||
</data>
|
||||
<data name="UnsupportedPlatform" xml:space="preserve">
|
||||
<value>The clipboard is not supported on this platform.</value>
|
||||
</data>
|
||||
<data name="AsHtmlUnsupported" xml:space="preserve">
|
||||
<value>The '-AsHtml' switch is not supported on this platform.</value>
|
||||
</data>
|
||||
<data name="TextFormatUnsupported" xml:space="preserve">
|
||||
<value>The '-TextFormatType' parameter only supports 'Text' on this platform.</value>
|
||||
</data>
|
||||
<data name="PathUnsupported" xml:space="preserve">
|
||||
<value>The '-Path' parameter is not supported on this platform.</value>
|
||||
</data>
|
||||
<data name="LiteralPathUnsupported" xml:space="preserve">
|
||||
<value>The '-LiteralPath' parameter is not supported on this platform.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
+3
-1
@@ -9,7 +9,7 @@ PowerShellVersion="3.0"
|
||||
NestedModules="Microsoft.PowerShell.Commands.Management.dll"
|
||||
HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855958'
|
||||
FunctionsToExport = @()
|
||||
AliasesToExport = @("gtz")
|
||||
AliasesToExport = @("gcb", "gtz", "scb")
|
||||
CmdletsToExport=@("Add-Content",
|
||||
"Clear-Content",
|
||||
"Clear-ItemProperty",
|
||||
@@ -17,6 +17,8 @@ CmdletsToExport=@("Add-Content",
|
||||
"Convert-Path",
|
||||
"Copy-ItemProperty",
|
||||
"Get-ChildItem",
|
||||
"Get-Clipboard",
|
||||
"Set-Clipboard",
|
||||
"Get-Content",
|
||||
"Get-ItemProperty",
|
||||
"Get-ItemPropertyValue",
|
||||
|
||||
+3
-1
@@ -9,9 +9,11 @@ PowerShellVersion="3.0"
|
||||
NestedModules="Microsoft.PowerShell.Commands.Management.dll"
|
||||
HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=855958'
|
||||
FunctionsToExport = @()
|
||||
AliasesToExport = @("gin", "gtz", "stz")
|
||||
AliasesToExport = @("gcb", "gin", "gtz", "scb", "stz")
|
||||
CmdletsToExport=@("Add-Content",
|
||||
"Clear-Content",
|
||||
"Get-Clipboard",
|
||||
"Set-Clipboard",
|
||||
"Clear-ItemProperty",
|
||||
"Join-Path",
|
||||
"Convert-Path",
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
Describe 'Clipboard cmdlet tests' -Tag CI {
|
||||
BeforeAll {
|
||||
$xclip = Get-Command xclip -CommandType Application -ErrorAction Ignore
|
||||
}
|
||||
|
||||
Context 'Text' {
|
||||
BeforeAll {
|
||||
$defaultParamValues = $PSdefaultParameterValues.Clone()
|
||||
$PSDefaultParameterValues["it:skip"] = ($IsWindows -and $env:PROCESSOR_ARCHITECTURE.Contains("arm")) -or ($IsLinux -and $xclip -eq $null)
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
$PSDefaultParameterValues = $defaultParamValues
|
||||
}
|
||||
|
||||
It 'Get-Clipboard returns what is in Set-Clipboard' {
|
||||
$guid = New-Guid
|
||||
Set-Clipboard -Value $guid
|
||||
Get-Clipboard | Should -BeExactly $guid
|
||||
}
|
||||
|
||||
It 'Get-Clipboard returns an array' {
|
||||
1,2 | Set-Clipboard
|
||||
$out = Get-Clipboard
|
||||
$out.Count | Should -Be 2
|
||||
$out[0] | Should -Be 1
|
||||
$out[1] | Should -Be 2
|
||||
}
|
||||
|
||||
It 'Get-Clipboard -Raw returns one item' {
|
||||
1,2 | Set-Clipboard
|
||||
(Get-Clipboard -Raw).Count | Should -Be 1
|
||||
Get-Clipboard -Raw | Should -BeExactly "1$([Environment]::NewLine)2"
|
||||
}
|
||||
|
||||
It 'Set-Clipboard -Append will add text' {
|
||||
'hello' | Set-Clipboard
|
||||
'world' | Set-Clipboard -Append
|
||||
Get-Clipboard -Raw | Should -BeExactly "hello$([Environment]::NewLine)world"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ Describe "Verify approved aliases list" -Tags "CI" {
|
||||
"Alias", "gal", "Get-Alias", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
|
||||
"Alias", "gbp", "Get-PSBreakpoint", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
|
||||
"Alias", "gc", "Get-Content", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
|
||||
"Alias", "gcb", "Get-Clipboard", $($FullCLR ), "ReadOnly", "", ""
|
||||
"Alias", "gcb", "Get-Clipboard", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", ""
|
||||
"Alias", "gci", "Get-ChildItem", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
|
||||
"Alias", "gcm", "Get-Command", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
|
||||
"Alias", "gcs", "Get-PSCallStack", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
|
||||
@@ -158,7 +158,7 @@ Describe "Verify approved aliases list" -Tags "CI" {
|
||||
"Alias", "sasv", "Start-Service", $($FullCLR -or $CoreWindows ), "ReadOnly", "", ""
|
||||
"Alias", "sbp", "Set-PSBreakpoint", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "", ""
|
||||
"Alias", "sc", "Set-Content", $($FullCLR ), "ReadOnly", "", ""
|
||||
"Alias", "scb", "Set-Clipboard", $($FullCLR ), "ReadOnly", "", ""
|
||||
"Alias", "scb", "Set-Clipboard", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", ""
|
||||
"Alias", "select", "Select-Object", $($FullCLR -or $CoreWindows -or $CoreUnix), "ReadOnly", "AllScope", ""
|
||||
"Alias", "set", "Set-Variable", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", ""
|
||||
"Alias", "shcm", "Show-Command", $($FullCLR -or $CoreWindows ), "ReadOnly", "", ""
|
||||
@@ -259,7 +259,7 @@ Describe "Verify approved aliases list" -Tags "CI" {
|
||||
"Cmdlet", "Get-Alias", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None"
|
||||
"Cmdlet", "Get-AuthenticodeSignature", "", $($FullCLR -or $CoreWindows ), "", "", "None"
|
||||
"Cmdlet", "Get-ChildItem", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None"
|
||||
"Cmdlet", "Get-Clipboard", "", $($FullCLR ), "", "", ""
|
||||
"Cmdlet", "Get-Clipboard", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None"
|
||||
"Cmdlet", "Get-CmsMessage", "", $($FullCLR -or $CoreWindows ), "", "", "None"
|
||||
"Cmdlet", "Get-Command", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None"
|
||||
"Cmdlet", "Get-ComputerInfo", "", $($FullCLR -or $CoreWindows ), "", "", "None"
|
||||
@@ -420,7 +420,7 @@ Describe "Verify approved aliases list" -Tags "CI" {
|
||||
"Cmdlet", "Set-Acl", "", $($FullCLR -or $CoreWindows ), "", "", "Medium"
|
||||
"Cmdlet", "Set-Alias", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "Medium"
|
||||
"Cmdlet", "Set-AuthenticodeSignature", "", $($FullCLR -or $CoreWindows ), "", "", "Medium"
|
||||
"Cmdlet", "Set-Clipboard", "", $($FullCLR ), "", "", ""
|
||||
"Cmdlet", "Set-Clipboard", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "Medium"
|
||||
"Cmdlet", "Set-Content", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "Medium"
|
||||
"Cmdlet", "Set-Date", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "Medium"
|
||||
"Cmdlet", "Set-ExecutionPolicy", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "Medium"
|
||||
|
||||
@@ -67,8 +67,8 @@ New-TemporaryFile,https://go.microsoft.com/fwlink/?LinkId=821836
|
||||
New-Guid,https://go.microsoft.com/fwlink/?LinkId=526920
|
||||
Format-Hex,https://go.microsoft.com/fwlink/?LinkId=526919
|
||||
Convert-String,https://go.microsoft.com/fwlink/?LinkId=528577
|
||||
Get-Clipboard,https://go.microsoft.com/fwlink/?LinkId=526219
|
||||
Set-Clipboard,https://go.microsoft.com/fwlink/?LinkId=526220
|
||||
Get-Clipboard,https://go.microsoft.com/fwlink/?LinkId=2109905
|
||||
Set-Clipboard,https://go.microsoft.com/fwlink/?LinkId=2109826
|
||||
Write-Information,https://go.microsoft.com/fwlink/?LinkId=525909
|
||||
Add-LocalGroupMember,https://go.microsoft.com/fwlink/?LinkId=717987
|
||||
Disable-LocalUser,https://go.microsoft.com/fwlink/?LinkId=717986
|
||||
|
||||
|
Reference in New Issue
Block a user