Hi I am creating a powershell script to read e-mail from outlook on which i have replied. can someone help me to find out the property in the variable.
all emails are in $monitor variable.
Add-type -assembly “Microsoft.Office.Interop.Outlook” | out-null
$olFolders = “Microsoft.Office.Interop.Outlook.olDefaultFolders” -as [type]
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace(“MAPI”)
$folder = $namespace.getDefaultFolder($olFolders::olFolderInBox)
$Monitor = $folder.Folders.Item("Test")
From https://stackoverflow.com/a/15323686/478656 and comments at https://www.slipstick.com/developer/code-samples/forward-messages-not-replied/ it looks like you want
$Email.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x10810003")
Which is the property for PR_LAST_VERB_EXECUTED, and the output is either 0 (not replied), 102 ('Reply') or 103 ('Reply All').
So maybe
$LastVerb = "http://schemas.microsoft.com/mapi/proptag/0x10810003"
$Monitor.Items | Where-Object { $_.PropertyAccessor.GetProperty($LastVerb) -gt 0 }
Related
I'm trying to do some kind of AD sync using USNChanged and retrieve all of the objects using the USNChanged property, but the entire process sounds a bit cryptic to me.
I have a PowerShell code that basically does what I need, but I was wondering you if anyone can help me convert it into a C# code. I would appreciate the help.
PS Code:
$highestCommittedUSN = (Get-ADRootDSE -server $preferredDC -properties * | select-object -property highestCommittedUSN).highestCommittedUSN
$lowUSN = 0
$highUSN = 0
for ($i=1000; $i -le $highestCommittedUSN ; $i=$i+10000 ) {
[system.gc]::Collect()
$error.clear()
$highUSN=$i
write-host "(&(usnChanged>=$lowUSN)(usnChanged<$highUSN))"
$adObjects = (Get-ADObject -LDAPFilter "(&(usnChanged>=$lowUSN)(usnChanged<=$highUSN))" -Server $preferredDC -Properties * -IncludeDeletedObjects)
($adObjects).count
if ($error.count -lt 0) {
for ($j=$lowUSN; $j -le 490767138; $j=$j+1 ) {
">>> " + $j
$adObjects = Get-ADObject -LDAPFilter "(usnChanged=$j)" -Server "DCName" -Properties * -IncludeDeletedObjects
$adObjects | ConvertTo-Json | Out-File -FilePath ff.json -Append
if ($error.count -ge 1) {
"There is problem with this USN " + $j + " on " + $preferredDC | Out-File -FilePath badUSN.txt -Append
$adObjects.distinguishedName
}
$adObjects.distinguishedName
}
}
$lowUSN=$highUSN
$adObjects.distinguishedName
$adObjects = $null
$error.clear()
}
I did found a similar question here : How to read "uSNChanged" property using C# , but I'm not sure if I can use that answer.
Have another head scratcher here, simply put my balloon notification does not work when fired from inside of a function that is inside of a job, the icon shows up for a fraction of a second and then disappears, tried several compinations of -wait -sleep -sleep-start to see if i could delay its "completion" since i feel the function is not running it's full course before ending, it works outside of the job/function, but inside it does not, here is the snippet I am calling
function MakeToolTip
{
[CmdletBinding(SupportsShouldProcess = $true)]
param
(
[Parameter(Mandatory=$true)]
$Text,
[Parameter(Mandatory=$true)]
$Title,
[ValidateSet(‘None’, ‘Info’, ‘Warning’, ‘Error’)]
$Icon = ‘Info’, $Timeout = 10000
)
Add-Type -AssemblyName System.Windows.Forms
if ($script:balloon -eq $null)
{
$script:balloon = New-Object System.Windows.Forms.NotifyIcon
}
$path = Get-Process -id $pid | Select-Object -ExpandProperty Path
$balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path)
$balloon.BalloonTipIcon = $Icon
$balloon.BalloonTipText = $Text
$balloon.BalloonTipTitle = $Title
$balloon.Visible = $true
$balloon.ShowBalloonTip($Timeout)
}
This is called with: MakeToolTip "Testing" "VNC Connections" Info
The full code of the script is here, lines 239-269: https://pastebin.com/7Q4gwLJe
I'm considering running the balloon in a separate job? Maybe the pipeline is completing it too quickly because there too much other stuff going on?
EDIT
Finding that when wrapped in a job a balloon notification does not work, very strange behavior
$MakeToolTip =
{
function Makeit {
[CmdletBinding(SupportsShouldProcess = $true)]
param
(
[Parameter(Mandatory=$true)]
$Text,
[Parameter(Mandatory=$true)]
$Title,
[ValidateSet(‘None’, ‘Info’, ‘Warning’, ‘Error’)]
$Icon = ‘Info’, $Timeout = 10000
)
Add-Type -AssemblyName System.Windows.Forms
if ($balloon -eq $null)
{
$balloon = New-Object System.Windows.Forms.NotifyIcon
}
$path = Get-Process -id $pid | Select-Object -ExpandProperty Path
$balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path)
$balloon.BalloonTipIcon = $Icon
$balloon.BalloonTipText = $Text
$balloon.BalloonTipTitle = $Title
$balloon.Visible = $true
$balloon.ShowBalloonTip($Timeout)
write-host $Text, $Title
}
}
$balloonjob = Start-Job -ScriptBlock {MakeIt 'Hi' 'There'} -InitializationScript $MakeToolTip -Name "BalloonJob"
Register-ObjectEvent $balloonjob -EventName StateChanged -Action {
if ($eventArgs.JobStateInfo.State -eq [System.Management.Automation.JobState]::Failed)
{
Write-Host "Closing the Balloon"
# This command removes the original job
$sender | Remove-Job -Force
# These commands remove the event registration
$eventSubscriber | Unregister-Event -Force
$eventSubscriber.Action | Remove-Job -Force
}
}
I need to get the Current Windows Keyboard Layout for my WPF application to map each key correctly and handle AZERTY as well as QWERTY and QWERTZ (and so on...)
I noticed a problem since I am working with a French layout (azerty) but my windows is displayed in English.
I tried various methods to get the layout correctly but without results :
var test1 = InputLanguageManager.Current.CurrentInputLanguage;
and
var test2 = CultureInfo.CurrentCulture;
I tried by having ENG language with AZERTY layout, ENG language with QWERTY layout and FRA language with AZERTY layout but the output from my tests were always different. I could get the language displayed correctly (en-GB) but not the layout.
The following PowerShell1 script declares Get-KeyboardLayoutForPid function which reliably gets the Current Windows Keyboard Layout for any process2.
if ( $null -eq ('Win32Functions.KeyboardLayout' -as [type]) ) {
Add-Type -MemberDefinition #'
[DllImport("user32.dll")]
public static extern IntPtr GetKeyboardLayout(uint thread);
'# -Name KeyboardLayout -Namespace Win32Functions
}
Function Get-KeyboardLayoutForPid {
[cmdletbinding()]
Param (
[parameter(Mandatory=$False, ValueFromPipeline=$False)]
[int]$Id = $PID,
# used formerly for debugging
[parameter(Mandatory=$False, DontShow=$True)]
[switch]$Raw
)
$InstalledInputLanguages = [System.Windows.Forms.InputLanguage]::InstalledInputLanguages
$CurrentInputLanguage = [System.Windows.Forms.InputLanguage]::DefaultInputLanguage # CurrentInputLanguage
$CurrentInputLanguageHKL = $CurrentInputLanguage.Handle # just an assumption
### Write-Verbose ('CurrentInputLanguage: {0}, 0x{1:X8} ({2}), {3}' -f $CurrentInputLanguage.Culture, ($CurrentInputLanguageHKL -band 0xffffffff), $CurrentInputLanguageHKL, $CurrentInputLanguage.LayoutName)
Function GetRealLayoutName ( [IntPtr]$HKL ) {
$regBase = 'Registry::' +
'HKLM\SYSTEM\CurrentControlSet\Control\Keyboard Layouts'
$LayoutHex = '{0:x8}' -f ($hkl -band 0xFFFFFFFF)
if ( ($hkl -band 0xFFFFFFFF) -lt 0 ) {
$auxKeyb = Get-ChildItem -Path $regBase |
Where-Object {
$_.Property -contains 'Layout Id' -and
(Get-ItemPropertyValue -Path "Registry::$($_.Name)" `
-Name 'Layout Id' `
-ErrorAction SilentlyContinue
) -eq $LayoutHex.Substring(2,2).PadLeft(4,'0')
} | Select-Object -ExpandProperty PSChildName
} else {
$auxKeyb = $LayoutHex.Substring(0,4).PadLeft(8,'0')
}
$KbdLayoutName = Get-ItemPropertyValue -Path (
Join-Path -Path $regBase -ChildPath $auxKeyb
) -ErrorAction SilentlyContinue -Name 'Layout Text'
$KbdLayoutName
# Another option: grab localized string from 'Layout Display Name'
} # Function GetRealLayoutName
Function GetKbdLayoutForPid {
Param (
[parameter(Mandatory=$True, ValueFromPipeline=$False)]
[int]$Id,
[parameter(Mandatory=$False, DontShow=$True)]
[string]$Parent = ''
)
$Processes = Get-Process -Id $Id
$Weirds = #('powershell_ise','explorer') # not implemented yet
$allLayouts = foreach ( $Proces in $Processes ) {
$LayoutsExtra = [ordered]#{}
$auxKLIDs = #( for ( $i=0; $i -lt $Proces.Threads.Count; $i++ ) {
$thread = $Proces.Threads[$i]
## The return value is the input locale identifier for the thread:
$LayoutInt = [Win32Functions.KeyboardLayout]::GetKeyboardLayout( $thread.Id )
$LayoutsExtra[$LayoutInt] = $thread.Id
})
Write-Verbose ('{0,6} ({1,6}) {2}: {3}' -f $Proces.Id, $Parent,
$Proces.ProcessName, (($LayoutsExtra.Keys |
Select-Object -Property #{ N='Handl';E={('{0:x8}' -f ($_ -band 0xffffffff))}} |
Select-Object -ExpandProperty Handl) -join ', '))
foreach ( $auxHandle in $LayoutsExtra.Keys ) {
$InstalledInputLanguages | Where-Object { $_.Handle -eq $auxHandle }
}
$ConHost = Get-WmiObject Win32_Process -Filter "Name = 'conhost.exe'"
$isConsoleApp = $ConHost | Where-Object { $_.ParentProcessId -eq $Proces.Id }
if ( $null -ne $isConsoleApp ) {
GetKbdLayoutForPid -Id ($isConsoleApp.ProcessId) -Parent ($Proces.Id -as [string])
}
}
if ( $null -eq $allLayouts ) {
# Write-Verbose ('{0,6} ({1,6}) {2}: {3}' -f $Proces.Id, $Parent, $Proces.ProcessName, '')
} else {
$allLayouts
}
} # GetKbdLayoutForPid
$allLayoutsRaw = GetKbdLayoutForPid -Id $Id
if ( $null -ne $allLayoutsRaw ) {
if ( ([bool]$PSBoundParameters['Raw']) ) {
$allLayoutsRaw
} else {
$retLayouts = $allLayoutsRaw |
Sort-Object -Property Handle -Unique |
Where-Object { $_.Handle -ne $CurrentInputLanguageHKL }
if ( $null -eq $retLayouts ) { $retLayouts = $CurrentInputLanguage }
$RealLayoutName = $retLayouts.Handle |
ForEach-Object { GetRealLayoutName -HKL $_ }
$ProcessAux = Get-Process -Id $Id
$retLayouts | Add-Member -MemberType NoteProperty -Name 'ProcessId' -Value "$Id"
$retLayouts | Add-Member -MemberType NoteProperty -Name 'ProcessName' -Value ($ProcessAux | Select-Object -ExpandProperty ProcessName )
# $retLayouts | Add-Member -MemberType NoteProperty -Name 'WindowTitle' -Value ($ProcessAux | Select-Object -ExpandProperty MainWindowTitle )
$retLayouts | Add-Member -MemberType NoteProperty -Name 'RealLayoutName' -Value ($RealLayoutName -join ';')
$retLayouts
}
}
<#
.Synopsis
Get the current Windows Keyboard Layout for a process.
.Description
Gets the current Windows Keyboard Layout for a process. Identify the process
using -Id parameter.
.Parameter Id
A process Id, e.g.
- Id property of System.Diagnostics.Process instance (Get-Process), or
- ProcessId property (an instance of the Win32_Process WMI class), or
- PID property from "TaskList.exe /FO CSV", …
.Parameter Raw
Parameter -Raw is used merely for debugging.
.Example
Get-KeyboardLayoutForPid
This example shows output for the current process (-Id $PID).
Note that properties RealLayoutName and LayoutName could differ (the latter is wrong; a bug in [System.Windows.Forms.InputLanguage] implementation?)
ProcessId : 2528
ProcessName : powershell
RealLayoutName : United States-International
Culture : cs-CZ
Handle : -268368891
LayoutName : US
.Example
. D:\PShell\tests\Get-KeyboardLayoutForPid.ps1 # activate the function
Get-Process -Name * |
ForEach-Object { Get-KeyboardLayoutForPid -Id $_.Id -Verbose }
This example shows output for each currently running process, unfortunately
even (likely unusable) info about utility/service processes.
The output itself can be empty for most processes, but the verbose stream
shows (hopefully worthwhile) info where current keboard layout is held.
Note different placement of the current keboard layout ID:
- console application (cmd, powershell, ubuntu): conhost
- combined GUI/console app (powershell_ise) : the app itself
- classic GUI apps (notepad, notepad++, …) : the app itself
- advanced GUI apps (iexplore) : Id ≘ tab
- "modern" GUI apps (MicrosoftEdge*) : Id ≟ tab (unclear)
- combined GUI/service app (explorer) : indiscernible
- etc… (this list is incomplete).
For instance, iexplore.exe creates a separate process for each open window
or tab, so their identifying and assigning input languages is an easy task.
On the other side, explorer.exe creates the only process, regardless of
open visible window(s), so they are indistinguishable by techniques used here…
.Example
gps -Name explorer | % { Get-KeyboardLayoutForPid -Id $_.Id } | ft -au
This example shows where the function could fail in a language multifarious environment:
ProcessId ProcessName RealLayoutName Culture Handle LayoutName
--------- ----------- -------------- ------- ------ ----------
5344 explorer Greek (220);US el-GR -266992632 Greek (220)
5344 explorer Greek (220);US cs-CZ 67699717 US
- scenario:
open three different file explorer windows and set their input languages
as follows (their order does not matter):
- 1st window: let default input language (e.g. Czech, in my case),
- 2nd window: set different input language (e.g. US English),
- 3rd window: set different input language (e.g. Greek).
- output:
an array (and note that default input language window isn't listed).
.Inputs
No object can be piped to the function. Use -Id pameter instead,
named or positional.
.Outputs
[System.Windows.Forms.InputLanguage] extended as follows:
note the <…> placeholder
Get-KeyboardLayoutForPid | Get-Member -MemberType Properties
TypeName: System.Windows.Forms.InputLanguage
Name MemberType Definition
---- ---------- ----------
ProcessId NoteProperty string ProcessId=<…>
ProcessName NoteProperty System.String ProcessName=powershell
RealLayoutName NoteProperty string RealLayoutName=<…>
Culture Property cultureinfo Culture {get;}
Handle Property System.IntPtr Handle {get;}
LayoutName Property string LayoutName {get;}
.Notes
To add the `Get-KeyboardLayoutForPid` function to the current scope,
run the script using `.` dot sourcing operator, e.g. as
. D:\PShell\tests\Get-KeyboardLayoutForPid.ps1
Auhor: https://stackoverflow.com/users/3439404/josefz
Created: 2019-11-24
Revisions:
.Link
.Component
P/Invoke
<##>
} # Function Get-KeyboardLayoutForPid
if ( -not ('System.Windows.Forms.InputLanguage' -as [type]) ) {
Add-Type -AssemblyName System.Windows.Forms
}
The Get-KeyboardLayoutForPid function contains a Comment-Based Help placed at the end of its body. I hope that its principle is implementable in C# easy.
The main idea of my approach:
Suppose that the current keyboard layout (CurrentInputLanguage) for a given process is the (user-dependant) default one (DefaultInputLanguage).
Collect keyboard layouts associated with every thread of given process (allLayoutsRaw). Note this trick for a console application: collect keyboard layouts associated with every thread of child conhost process as well.
If there is a keyboard layout different from DefaultInputLanguage in the allLayoutsRaw collection then it's the sought-after one (retLayouts).
1 Does not work in PowerShell Core (pwsh.exe).
2 Might fail for explorer process in a language multifarious environment, see an example of failing scenario in the Comment-Based help.
I am not sure of the ask - whether you want to know the current keyboard layout or you want to set the keyboard layout.
In both cases, InputLanguageManager should help.
You can try setting input language manager to appropriate cultureInfo object.
This should change the keyboard layout for your WPF application
InputLanguageManager.Current.CurrentInputLanguage = new CultureInfo("fr-FR");
For a software update, I need to know if a specific service runs on all computers. And if not, I need to start this service on the missing devices.
Is there a possibility to realize this in C# or PowerShell?
In PowerShell you'd use the *-Service cmdlets. Get-Service can query services on remote hosts via its -ComputerName parameter. The returned services can then be filtered and piped into Start-Service:
$servers = 'FOO', 'BAR', 'BAZ', ...
Get-Service -ComputerName $servers -Name 'svcname' |
? { $_.Status -eq 'Stopped' } |
Start-Service
How to find computers running a particular service has already been answered here:
how to get a pc list that have a service running on each pc?
you should then be able to run Start-Service -Name <Service Name>
I ended up with a mix of all suggestions here and wrote a powershell script.
Any improvements are much appreciated.
$strFilter = "computer"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.SearchScope = "Subtree"
$objSearcher.PageSize = 1000
$objSearcher.Filter = "(objectCategory=$strFilter)"
$colResults = $objSearcher.FindAll()
$counter = 0
foreach ($i in $colResults)
{
$objComputer = $i.GetDirectoryEntry()
if (Test-Connection -Computername $objComputer.Name -BufferSize 16 -Count 1 -Quiet) {
Get-Service -ComputerName $objComputer.Name -Name 'svcname' | ? { $_.Status -eq 'Stopped' } | Start-Service
}
$counter++
Write-Host "finished " + $counter
}
I'm trying to put something together that will use the AD Thumbnail photo to set a user's account picture on Windows 8. It seems like I should be able to use the API from WinRT to do this. I've pieced something together from various sources about calling the API from powershell, but I can't get it working. Here's an example of what I've tried to do:
$photo = ([ADSISEARCHER]“samaccountname=$($username)”).findone().properties.thumbnailphoto
$path = "C:\temp\Photo.jpg"
$photo | set-content $path -encoding byte
[Windows.System.UserProfile.UserInformation,Windows.System.UserProfile,ContentType=WindowsRuntime] > $null
[Windows.System.UserProfile.UserInformation]::SetAccountPictureAsync($photo)
I've tried a couple of other variations, but no matter what I do, I end up with an error like this:
Cannot convert argument "image", with value: "System.Object[]", for "setAccountPictureAsync" to type "Windows.Storage.IStorageFile" . . .
Is there something simple that I'm missing here to make this work?
I found this blog post by Keith Hill which seems like it might be helpful, but I am not sure if it directly translates to the issue I'm having.
Thanks!
Aurock
https://fleexlab.blogspot.com/2018/02/using-winrts-iasyncoperation-in.html has a pure-PowerShell solution.
Add-Type -AssemblyName System.Runtime.WindowsRuntime
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
function Await($WinRtTask, $ResultType) {
$asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
$netTask = $asTask.Invoke($null, #($WinRtTask))
$netTask.Wait(-1) | Out-Null
$netTask.Result
}
This could then be used as:
$photoPath = "$home\Pictures\Photo.jpg"
$file = Await ([Windows.Storage.StorageFile]::GetFileFromPathAsync($photoPath)) ([Windows.Storage.StorageFile])
$result = Await ([Windows.System.UserProfile.UserInformation]::SetAccountPictureAsync($file)) ([Windows.System.UserProfile.SetAccountPictureResult])
SetAccountPicture expects an object implementing IStorageFile and not a byte array. I would save the picture to your Pictures folder then load that into a StorageFile as shown below. You should be able to pass that object into the SetAccountPicture() method e.g.
$photoPath = "$home\Pictures\Photo.jpg"
$asyncOp = [Windows.Storage.StorageFile]::GetFileFromPathAsync($photoPath)
$typeName = 'PoshWinRT.AsyncOperationWrapper[Windows.Storage.StorageFile]'
$wrapper = new-object $typeName -Arg $asyncOp
$file = $wrapper.AwaitResult()
$asyncOp = [Windows.System.UserProfile.UserInformation]::SetAccountPictureAsync($file)
$typeName = 'PoshWinRT.AsyncOperationWrapper[Windows.System.UserProfile.SetAccountPictureResult]'
$wrapper = new-object $typeName -Arg $asyncOp
$result = $wrapper.AwaitResult()
$wrapper.Dispose()