I have custom command and I need to apply autocomplete for some values by take my character and find the values that have these characters
ex:
$customName= {
param ($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParams)
('abcd', 'efg') | Where-Object { $_.Name -like "$WordToComplete*" } | ForEach-Object { "$_" }
}
Register-ArgumentCompleter -CommandName xstart -ParameterName blueprintName -ScriptBlock $customName
I need when enter
xstart ab and click tab then complete it to abcd
Related
Consider following code:
Function ShowSave-Log {
Param ([Parameter(Mandatory=$true)][String] $text)
$PSDefaultParameterValues=#{'Out-File:Encoding' = 'utf8'}
$date=[string](Get-Date).ToString("yyyy/MM/dd HH:mm:ss")
Tee-Object -InputObject "$date $text" -FilePath $LOG_FILE -Append
#Write-Host "$date $text"
}
Function Is-Installed {
Param ([parameter(Mandatory=$true)][String] $app_name, [String] $app_version)
$apps = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" |
Select-Object DisplayName, DisplayVersion
$apps += Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" | Select-Object DisplayName, DisplayVersion
$apps = $apps.Where{$_.DisplayName -like "$app_name"}
if ($apps.Count -eq 0) {
ShowSave-Log "`'$app_name`' not found in the list of installed applications."
return $false
} else {
ShowSave-Log "`'$app_name`' is installed."
return $true
}
}
$LOG_FILE="$Env:TEMP\LOG.log"
if (Is-Installed "Notepad++ (64-bit x64)") {Write-Host "TRUE"}
I'd expect to see message from Tee-Object command in ShowSave-Log function, however it is never shown in terminal. I am guessing it's because it is called from 'if' statement. How can I get Tee-Object output to terminal screen ? It is saved to log file.
BTW Write-Host command correctly outputs message to terminal.
I am using PowerShell ISE, Visual Studio code and PowerShell terminal. PowerShell version 5.1
There is a common misconception about how Powershell functions return data. Actually there isn't a single return value or object as you are used to from other programming languages. Instead, there is an output stream of objects.
There are several ways to add data to the output stream, e. g.:
Write-Output $data
$data
return $data
Confusing to PS newcomers coming from other languages is the fact that return $data does not define the sole "return value" of a function. It is just a convenient way to combine Write-Output $data with an early exit from the function. Whatever data that was written to the output stream befor the return statement also contributes to the output of the function!
Analysis of the code
Tee-Object -InputObject "$date $text" -FilePath $LOG_FILE -Append
... appends the InputObject to the output stream of ShowSave-Log
ShowSave-Log "`'$app_name`' is installed."
... appends the message to the output stream of Is-Installed
return $true
... appends the value $true to the output stream of Is-Installed
Now we actually have two objects in the output stream of Is-Installed, the string message and the $true value!
if (Is-Installed "Notepad++ (64-bit x64)") {Write-Host "TRUE"}
Let me split up the if-statement to explain in detail what it does:
$temp = Is-Installed "Notepad++ (64-bit x64)"
... redirects the output stream of Is-Installed to temporary variable. As the output stream has been stored into a variable, it won't go further up in the function call chain, so it won't show up in the console anymore! That's why you don't see the message from Tee-Object.
In our case there is more than one object in the output stream, so the variable will be an array like #('... is installed', $true)
if ($temp) {Write-Host "TRUE"}
... does an implicit boolean conversion of the array $temp. A non-empty array converts to $true. So there is a bug here, because the function Is-Installed always "returns" a non-empty array. When the software is not installed, $temp would look like #('... not found ...', $false), which also converts to $true!
Proof:
$temp = Is-Installed "nothing"
$temp.GetType().Name # Prints 'Object[]'
$temp[0] # Prints '2020.12.13 12:39:37 'nothing' not found ...'
$temp[1] # Prints 'False'
if( $temp ) {'Yes'} # Prints 'Yes' !!!
How can I get Tee-Object output to terminal screen?
Don't let it write to the output stream, which should be used only for actual data to be "returned" from a function, not for log messages.
A simple way to do that is to redirect the output of Tee-Object to Write-Host, which writes to the information stream:
Tee-Object -InputObject "$date $text" -FilePath $LOG_FILE -Append | Write-Host
A more sensible way would be to redirect to the verbose stream:
Tee-Object -InputObject "$date $text" -FilePath $LOG_FILE -Append | Write-Verbose
Now the log message doesn't clutter the terminal by default. Instead, to see detailed logging the caller has to enable verbose output, e. g. by setting $VerbosePreference = 'Continue' or calling the function with -Verbose parameter:
if( Is-Installed 'foo' -Verbose ){<# do something #>}
It might be easier to understand if you think of it as
$result = Is-Installed "Notepad++ (64-bit x64)"
if ($result) {Write-Host "TRUE"}
It's pretty clear that way that the result isn't output to the console at any time.
You may also be misunderstanding how return works
ShowSave-Log "`'$app_name`' not found in the list of installed applications."
return $false
is functionally the same as
ShowSave-Log "`'$app_name`' not found in the list of installed applications."
$false
return
You'd be better of having your functions return simple PowerShell objects rather than human readable text and truth values.
function Get-InstalledApps {
param (
[parameter(Mandatory=$true)][string] $app_name,
[string] $app_version
)
$installPaths = #(
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
Get-ItemProperty -Path $installPaths | Where-Object DisplayName -like $app_name
}
And leave the formatting for the user to the top level of your script.
It could be worth looking at custom types with the DefaultDisplayPropertySet property. For example:
Update-TypeData -TypeName 'InstalledApp' -DefaultDisplayPropertySet 'DisplayName', 'DisplayVersion'
function Get-InstalledApps {
param (
[parameter(Mandatory=$true)][string] $app_name,
[string] $app_version
)
$installPaths = #(
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
Get-ItemProperty -Path $installPaths | Where-Object DisplayName -like $app_name | Add-Member -TypeName 'InstalledApp' -PassThru
}
Or without a custom type, this abomination of a one liner:
Get-ItemProperty -Path $installPaths | Where-Object DisplayName -like $app_name | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value ([System.Management.Automation.PSMemberInfo[]](New-Object System.Management.Automation.PSPropertySet DefaultDisplayPropertySet, ([string[]]('DisplayName', 'DisplayVersion')))) -PassThru
Also worth taking a look at is the Approved Verbs for PowerShell page.
In my adventure trying to learn Powershell, I am working on an extension on a script I have made. The idea is to make script there by adding ".iso" files into a folder. It will use that content in a menu so that I later can use it to select an iso file for a WM in Hyper-V
This is my version of how it will get the content in the first place
Get-ChildItem -Path C:\iso/*.iso -Name > C:\iso/nummer-temp.txt
Add-Content -Path C:\iso/nummer.txt ""
Get-Content -Path C:\iso/nummer-temp.txt | Add-Content -Path C:\iso/nummer.txt
When this code is run it will send an output like what i want. But my question is how do I use this output in a menu?
This is the best practice way to do so in powershell :
#lets say your .txt files gets this list after running get-content
$my_isos = $('win7.iso','win8.iso','win10.iso')
$user_choice = $my_isos | Out-GridView -Title 'Select the ISO File you want' -PassThru
#waiting till you choose the item you want from the grid view
Write-Host "$user_choice is going to be the VM"
I wouldn't try to make it with System.windows.forms utilities as i mentioned in my comment, unless you want to present the form more "good looking".
If you don't want to go for a graphical menu, but rather a console menu, you could use this function below:
function Show-Menu {
Param(
[Parameter(Position=0, Mandatory=$True)]
[string[]]$MenuItems,
[string] $Title
)
$header = $null
if (![string]::IsNullOrWhiteSpace($Title)) {
$len = [math]::Max(($MenuItems | Measure-Object -Maximum -Property Length).Maximum, $Title.Length)
$header = '{0}{1}{2}' -f $Title, [Environment]::NewLine, ('-' * $len)
}
# possible choices: digits 1 to 9, characters A to Z
$choices = (49..57) + (65..90) | ForEach-Object { [char]$_ }
$i = 0
$items = ($MenuItems | ForEach-Object { '{0} {1}' -f $choices[$i++], $_ }) -join [Environment]::NewLine
# display the menu and return the chosen option
while ($true) {
cls
if ($header) { Write-Host $header -ForegroundColor Yellow }
Write-Host $items
Write-Host
$answer = (Read-Host -Prompt 'Please make your choice').ToUpper()
$index = $choices.IndexOf($answer[0])
if ($index -ge 0 -and $index -lt $MenuItems.Count) {
return $MenuItems[$index]
}
else {
Write-Warning "Invalid choice.. Please try again."
Start-Sleep -Seconds 2
}
}
}
Having that in place, you call it like:
# get a list if iso files (file names for the menu and full path names for later handling)
$isoFiles = Get-ChildItem -Path 'D:\IsoFiles' -Filter '*.iso' -File | Select-Object Name, FullName
$selected = Show-Menu -MenuItems $isoFiles.Name -Title 'Please select the ISO file to use'
# get the full path name for the chosen file from the $isoFiles array
$isoToUse = ($isoFiles | Where-Object { $_.Name -eq $selected }).FullName
Write-Host "`r`nYou have selected file '$isoToUse'"
Example:
Please select the ISO file to use
---------------------------------
1 Win10.iso
2 Win7.iso
3 Win8.iso
Please make your choice: 3
You have selected file 'D:\IsoFiles\Win8.iso'
I'm trying to create a powershell script that will grab all Active Directory accounts that are enabled, and inactive for 90 days. The script will prompt the user to choose between querying computer or user accounts.
Depending on the choice, it will pass it over to the main command as a variable.
The commands work correctly if I don't pass a variable.
I'm not sure if what I'm trying to do is possible.
Sorry for any bad code formatting. Just starting out.
Clear-Host
write-host "`nProgram searches for Enabled AD users account that have not logged in for more than 90 days. `nIt searches the entire domain and saves the results to a CSV file on users desktop." "`n"
$choice = Read-host -Prompt " What do you want to search for Computer or Users Accounts`nType 1 for users`nType 2 for Computers`n`nChoice"
$account
if ($choice -eq 1) {
$account = UsersOnly
}
Elseif ($choice -eq 2) {
$account = ComputersOnly
}
Else {
write-host "This is not an option `n exiting program"
exit
}
$FileName = Read-Host -Prompt "What do you want to name the CSV file"
$folderPath = "$env:USERPROFILE\Desktop\$FileName.csv"
Search-ADAccount -AccountInactive -TimeSpan 90 -$account | Where-Object { $_.Enabled -eq $true } | select Name, UserPrincipalName, DistinguishedName | Export-Csv -Path $folderPath
Splatting is the way to achieve this. It's so named because you reference a variable with # instead of $ and # kind of looks a "splat".
it works by creating a hashtable, which is a type of dictionary (key/value pairs). In PowerShell we create hashtable literals with #{}.
To use splatting you just make a hashtable where each key/value pair is a parameter name and value, respectively.
So for example if you wanted to call Get-ChildItem -LiteralPath $env:windir -Filter *.exe you could also do it this way:
$params = #{
LiteralPath = $env:windir
Filter = '*.exe'
}
Get-ChildItem #params
You can also mix and match direct parameters with splatting:
$params = #{
LiteralPath = $env:windir
Filter = '*.exe'
}
Get-ChildItem #params -Verbose
This is most useful when you need to conditionally omit a parameter, so you can turn this:
if ($executablesOnly) {
Get-ChildItem -LiteralPath $env:windir -Filter *.exe
} else {
Get-ChildItem -LiteralPath $env:windir
}
Into this:
$params = #{
LiteralPath = $env:windir
}
if ($executablesOnly) {
$params.Filter = '*.exe'
}
Get-ChildItem #params
or this:
$params = #{}
if ($executablesOnly) {
$params.Filter = '*.exe'
}
Get-ChildItem -LiteralPath $env:windir #params
With only 2 possible choices, the if/else doesn't look that bad, but as your choices multiply and become more complicated, it gets to be a nightmare.
Your situation: there's one thing I want to note first. The parameters you're trying to alternate against are switch parameters. That means when you supply them you usually only supply the name of the parameter. In truth, these take boolean values that default to true when the name is supplied. You can in fact override them, so you could do Search-ADAccount -UsersOnly:$false but that's atypical.
Anyway the point of mentioning that is that it may have been confusing how you would set its value in a hashtable for splatting purposes, but the simple answer is just give them a boolean value (and usually it's $true).
So just changing your code simply:
$account = if ($choice -eq 1) {
#{ UsersOnly = $true }
} elseif ($choice -eq 2) {
#{ ComputersOnly = $true }
}
# skipping some stuff
Search-ADAccount -AccountInactive -TimeSpan 90 #account
I also put the $account assignment on the left side of the if instead of inside, but that's your choice.
Question
Is it possible to force PowerShell to export to CSV in French format when run in a Windows Session with en-GB culture?
More Info
I'm hoping to export some data to CSV using the French culture rules (i.e. CSV's delimiter set to semicolon, but also with numbers using commas for decimal places, and other cultural formatting differences; so just using the -Delimiter parameter is not sufficient).
I came up with the below code (based on https://stackoverflow.com/a/7052955/361842)
function Set-Culture
{
[CmdletBinding(DefaultParameterSetName='ByCode')]
param (
[Parameter(Mandatory,ParameterSetName='ByCode',Position=1)]
[string] $CultureCode
,
[Parameter(Mandatory,ParameterSetName='ByCulture',Position=1)]
[System.Globalization.CultureInfo] $Culture
)
begin {
[System.Globalization.CultureInfo] $Culture = [System.Globalization.CultureInfo]::GetCultureInfo($CultureCode)
}
process {
[System.Threading.Thread]::CurrentThread.CurrentUICulture = $Culture
[System.Threading.Thread]::CurrentThread.CurrentCulture = $Culture
}
}
function Invoke-CommandInCulture {
[CmdletBinding()]
param (
[Parameter(Mandatory,ParameterSetName='ByCode',Position=1)]
[string]$CultureCode
,
[Parameter(Mandatory,Position=2)]
[ScriptBlock]$Code
)
process {
$OriginalCulture = Get-Culture
try
{
Set-Culture $CultureCode
Write-Verbose (Get-Culture) #this always returns en-GB
Invoke-Command -ScriptBlock $Code
}
finally
{
Set-Culture $OriginalCulture
}
}
}
The following code implies that this method works:
Invoke-CommandInCulture -CultureCode 'fr' -Code {
[System.Threading.Thread]::CurrentThread.CurrentUICulture
[System.Threading.Thread]::CurrentThread.CurrentCulture
} #shows that the command's thread's culture is French
Invoke-CommandInCulture -CultureCode 'fr' -Code {
get-date
} #returns the current date in French
However PowerShell has it's own idea of what's going on
Invoke-CommandInCulture -CultureCode 'fr' -Code {
get-culture
"PSCulture: $PSCulture"
"PSUICulture: $PSUICulture"
} #returns my default (en-GB) culture; not the thread's culture
And this impacts the logic for converting to CSV:
Invoke-CommandInCulture -CultureCode 'fr' -Code {
get-process | ConvertTo-CSV -UseCulture
} #again, uses my default culture's formatting rules; not the FR ones
Workaround #1: Custom Function to Convert Values to Strings in Given Culture
Here's a workaround solution; converting each field to a string using the given culture, then converting the string values to a CSV:
function ConvertTo-SpecifiedCulture {
[CmdletBinding()]
param (
[Parameter(Mandatory,ValueFromPipeline)]
[PSObject]$InputObject
,
[Parameter(Mandatory)]
[string]$CultureCode
,
[Parameter(ParameterSetName='DefaultParameter', Position=0)]
[System.Object[]]$Property
)
begin {
[System.Globalization.CultureInfo] $Culture = [System.Globalization.CultureInfo]::GetCultureInfo($CultureCode)
}
process {
if($Property -eq $null) {$Property = $InputObject.PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames}
$Result = new-object -TypeName PSObject -Property #{}
$Property | %{
$Result | Add-Member -MemberType NoteProperty -Name $_ -Value ($InputObject."$_").ToString($Culture)
}
$Result
}
}
Get-Process | select -first 2 | ConvertTo-SpecifiedCulture -CultureCode 'fr' | ConvertTo-CSV -Delimiter ';'
Workaround #2: Override Current Culture to Match Target Culture
Another option is to change the settings of the current culture so that it shares those of the required culture. This feels more hacky; though depending on scenario may work out cleaner/more practical than the above.
e.g. to use FR's number format we just update the current culture's number format to match FR's:
$(Get-Culture).NumberFormat = ([System.Globalization.CultureInfo]'FR').NumberFormat
...and we can do likewise for the remaining (settable) properties:
function Set-CurrentCulture {
[CmdletBinding()]
param (
[string]$CultureCode
)
begin {
$Global:FakedCurrentCulture = $CultureCode #in case we need a reference to the current culture's name
[System.Globalization.CultureInfo]$NewCulture = [System.Globalization.CultureInfo]::GetCultureInfo($CultureCode)
[System.Globalization.CultureInfo]$ReferenceToCurrentCulture = Get-Culture
Write-Verbose "Switching Defintion to $($NewCulture.Name)"
}
process {
#NB: At time of writing, the only settable properties are NumberFormatInfo & DateTimeFormatInfo
$ReferenceToCurrentCulture.psobject.properties | ?{$_.isSettable} | %{
$propertyName = $_.Name
write-verbose "Setting property $propertyName"
write-verbose "- from: $($ReferenceToCurrentCulture."$propertyName")"
write-verbose "- to: $($NewCulture."$propertyName")"
$ReferenceToCurrentCulture."$propertyName" = $NewCulture."$propertyName"
}
#ListSeparator
$ReferenceToCurrentCulture.TextInfo.psobject.properties | ?{$_.isSettable} | %{
$propertyName = $_.Name
write-verbose "Setting property TextInfo.$propertyName"
write-verbose "- from: $($ReferenceToCurrentCulture.TextInfo."$propertyName")"
write-verbose "- to: $($NewCulture.TextInfo."$propertyName")"
$ReferenceToCurrentCulture.TextInfo."$propertyName" = $NewCulture."$propertyName"
}
#for some reason this errors
#Localized, TwoDigitYearMax
<#
$ReferenceToCurrentCulture.Calendar.psobject.properties | ?{$_.isSettable} | %{
$propertyName = $_.Name
write-verbose "Setting property Calendar.$propertyName"
write-verbose "- from: $($ReferenceToCurrentCulture.Calendar."$propertyName")"
write-verbose "- to: $($NewCulture.Calendar."$propertyName")"
$ReferenceToCurrentCulture.Calendar."$propertyName" = $NewCulture."$propertyName"
}
#>
}
}
function Reset-CurrentCulture {
[CmdletBinding()]
param ()
process {
Set-CurrentCulture -CultureCode ((get-culture).Name)
}
}
function Test-It {
[CmdletBinding()]
param ()
begin {
write-verbose "Current Culture: $Global:FakedCurrentCulture"
}
process {
1..5 | %{
New-Object -TypeName PSObject -Property #{
Integer = $_
String = "Hello $_"
Numeric = 2.139 * $_
Money = (2.139 * $_).ToString('c')
Date = (Get-Date).AddDays($_)
}
} | ConvertTo-Csv -NoTypeInformation
}
}
Set-CurrentCulture 'fr' -Verbose
Test-It
Set-CurrentCulture 'en-GB' -Verbose
Test-It
Set-CurrentCulture 'en-US' -Verbose
Test-It
Set-CurrentCulture 'ar-DZ' -Verbose
Test-It
Reset-CurrentCulture -Verbose
Test-It
We could potentially go further and look at overwriting the read only properties (this is possible: https://learn-powershell.net/2016/06/27/quick-hits-writing-to-a-read-only-property/)... but this already feels very nasty; so I'm not going to go there as the above was sufficient for my needs.
EDIT: 23 Oct 2020
See postanote's answer.
EDIT: 14 May 2015
After 3 years, I thought I would share my ClipboardModule (I hope I am allowed to):
Add-Type -AssemblyName System.Windows.Forms
Function Get-Clipboard {
param([switch]$SplitLines)
$text = [Windows.Forms.Clipboard]::GetText();
if ($SplitLines) {
$xs = $text -split [Environment]::NewLine
if ($xs.Length -gt 1 -and -not($xs[-1])) {
$xs[0..($xs.Length - 2)]
} else {
$xs
}
} else {
$text
}
}
function Set-Clipboard {
$in = #($input)
$out =
if ($in.Length -eq 1 -and $in[0] -is [string]) { $in[0] }
else { $in | Out-String }
if ($out) {
[Windows.Forms.Clipboard]::SetText($out);
} else {
# input is nothing, therefore clear the clipboard
[Windows.Forms.Clipboard]::Clear();
}
}
function GetSet-Clipboard {
param([switch]$SplitLines, [Parameter(ValueFromPipeLine=$true)]$ObjectSet)
if ($input) {
$ObjectSet = $input;
}
if ($ObjectSet) {
$ObjectSet | Set-Clipboard
} else {
Get-Clipboard -SplitLines:$SplitLines
}
}
Set-Alias cb GetSet-Clipboard
Export-ModuleMember -Function *-* -Alias *
I usually use the cb alias (for GetSet-Clipboard) because it is two way i.e can get or set the clipboard:
cb # gets the contents of the clipboard
"john" | cb # sets the clipboard to "john"
cb -s # gets the clipboard and splits it into lines
If you have WMF 5.0, PowerShell contains two new cmdlets:
get-clipboard and set-clipboard
EDIT: Please look at question instead for solution.
Here is my solution:
Add-Type -AssemblyName 'System.Windows.Forms'
filter Set-Clipboard {
begin {
$cp = #()
}
process {
$_ | Tee-Object -Variable 'cp0'
$cp = $cp + #($cp0);
}
end {
$str = ($cp | Out-String).ToString();
[Windows.Forms.Clipboard]::Clear();
if ( ($str -ne $null) -and ($str -ne '') ) {
[Windows.Forms.Clipboard]::SetText( $str )
}
$cp = #()
}
}
This collects all the objects in an array, $cp. We use Tee-Object to redirect the current element, $_, to both the next process and to store it in the array, $cp. Lastly, once the process is finished we set the clipboard's text.
I have used it in the following way:
dir -Recurse | Set-Clipboard | Select 'Name'
And it seems to work.
To use a function instead:
function Set-Clipboard-Func {
$str = $input | Out-String
[Windows.Forms.Clipboard]::Clear();
if ( ($str -ne $null) -and ($str -ne '') ) {
[Windows.Forms.Clipboard]::SetText( $str )
}
}
Powershell version 6.1 removed this commandlet, so it is no longer built-in.
Instead, you need to install the ClipboardText package. In Powershell's console type:
Install-Module -Name ClipboardText
Then you can use:
Set-ClipboardText "hello clipboard"
Get-ClipboardText
Here is the github issue with the maintainers of Powershell redirecting you to use the ClipboardText package.
Native clip cmdlets in PSv7
$Host
# Results
<#
Name : ConsoleHost
Version : 7.0.3
InstanceId : 54be9bfd-799d-4213-a13a-22403c1d9ed8
UI : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture : en-US
CurrentUICulture : en-US
PrivateData : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
DebuggerEnabled : True
IsRunspacePushed : False
Runspace : System.Management.Automation.Runspaces.LocalRunspace
#>
Get-Command -Name '*clip*'|Format-Table -a
# Results
<#
CommandType Name Version Source
----------- ---- ------- ------
Function Get-Clipboard 1.3.6 PowerShellCookbook
Function Set-Clipboard 1.3.6 PowerShellCookbook
Function Start-ClipboardHistoryViewer 0.0 ModuleLibrary
Cmdlet Get-Clipboard 7.0.0.0 Microsoft.PowerShell.Management
Cmdlet Set-Clipboard 7.0.0.0 Microsoft.PowerShell.Management
Cmdlet Set-UDClipboard 2.9.0 UniversalDashboard
Application clip.exe 10.0.19041.1 C:\WINDOWS\system32\clip.exe
Application ClipRenew.exe 10.0.19041.1 C:\WINDOWS\system32\ClipRenew.exe
Application ClipUp.exe 10.0.19041.488 C:\WINDOWS\system32\ClipUp.exe
Application rdpclip.exe 10.0.19041.423 C:\WINDOWS\system32\rdpclip.exe
#>
get-clipboard
skips newline characters when text is entered sequentially.
I use
[System.Windows.Forms.Clipboard]::GetText()
as before.
Now that Get-clipboard and Set-Clipboard are built in PSv7
You can have this function in your profile:
"C:\Users<USER_ID>\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1"
function To-Notepad {
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[object]
$InputObject
)
begin { $objs = #() }
process { $objs += $InputObject }
end {
$old = Get-clipboard # store current value
$objs | out-string -width 1000 | Set-Clipboard
& "notepad2" /c
sleep -mil 500
$old | Set-Clipboard # restore the original value
}
}
And then use in this way:
dir -Path C:\Temp | To-Notepad