# this is the decimal we want to decipher $rawflags = 56823
# define an enum with the friendly names for the flags # don't forget [Flags] # IMPORTANT: you cannot change your type inside a PowerShell session! # if you made changes to the enum, close PowerShell and open a new # PowerShell! $enum = ' using System; [Flags] public enum BitFlags { None = 0, Option1 = 1, Option2 = 2, Option3 = 4, Option4 = 8, Option5 = 16, Option6 = 32, Option7 = 64, Option8 = 128, Option9 = 256, Option10= 512, Option11= 1024, Option12= 2048, Option13= 4096, Option14= 8192, Option15= 16384, Option16= 32768, Option17= 65536 } ' Add-Type-TypeDefinition$enum
# convert the decimal to the new enum [BitFlags]$flags = $rawflags $flags
# test individual flags $flags.HasFlag([BitFlags]::Option1) $flags.HasFlag([BitFlags]::Option2)
#requires -Version 5 classAppInstance : System.Diagnostics.Process { # Constructor, being called when you instantiate a new object of # this class AppInstance([string]$Name) : base() { # launch the process, get a regular process object, and then # enhance it with additional functionality $this.StartInfo.FileName = $Name $this.Start() $this.WaitForInputIdle() }
# for example, rename an existing method [void]Stop() { $this.Kill() }
# or invent new functionality # Close() closes the window gracefully. Unlike Kill(), # the user gets the chance to save unsaved work for # a specified number of seconds before the process # is killed [void]Close([Int]$Timeout = 0) { # send close message $this.CloseMainWindow() # wait for success if ($Timeout-gt0) { $null = $this.WaitForExit($Timeout * 1000) } # if process still runs (user aborted request), kill forcefully if ($this.HasExited -eq$false) { $this.Stop() } }
# example of how to change a property like process priority [void]SetPriority([System.Diagnostics.ProcessPriorityClass] $Priority) { $this.PriorityClass = $Priority }
[System.Diagnostics.ProcessPriorityClass]GetPriority() { if ($this.HasExited -eq$false) { return$this.PriorityClass } else { Throw"Process PID $($this.Id) does not run anymore." } }
# add static methods, for example a way to list all processes # variant A: no arguments static[System.Diagnostics.Process[]] GetAllProcesses() { return [AppInstance]::GetAllProcesses($false) } # variant B: submit $false to see only processes that have a window static[System.Diagnostics.Process[]] GetAllProcesses([bool]$All) { if ($All) { returnGet-Process } else { returnGet-Process | Where-Object { $_.MainWindowHandle -ne0 } } } }
# you can always run static methods [AppInstance]::GetAllProcesses($true) | Out-GridView-Title'All Processes' [AppInstance]::GetAllProcesses($false) | Out-GridView-Title'Processes with Window'
# this is how you instantiate a new process and get back # a new enhanced process object # classic way: # $notepad = New-Object -TypeName AppInstance('notepad') # new (and faster) way in PowerShell 5 to instantiate new objects: $notepad = [AppInstance]::new('notepad')
# set a different process priority $notepad.SetPriority('BelowNormal')
# add some text to the editor to see the close message Start-Sleep-Seconds5
# close the application and offer to save changes for a maximum # of 10 seconds $notepad.Close(10)
#requires -Version 5 # this enum works in PowerShell 5 only # in earlier versions, simply remove the enum, # and use the numbers for the desired window state # directly
# the C#-style signature of an API function (see also www.pinvoke.net) $code = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
# add signature as new type to PowerShell (for this session) $type = Add-Type-MemberDefinition$code-Name myAPI -PassThru
# access a process # (in this example, we are accessing the current PowerShell host # with its process ID being present in $pid, but you can use # any process ID instead) $process = Get-Process-Id$PID
# get the process window handle $hwnd = $process.MainWindowHandle
# apply a new window size to the handle, i.e. hide the window completely $type::ShowWindowAsync($hwnd, [ShowStates]::Hide)
Start-Sleep-Seconds2 # restore the window handle again $type::ShowWindowAsync($hwnd, [ShowStates]::Show)
Context 'PS Versioning' { It 'is current version' { $host.Version.Major -ge5-and$host.Version.Minor -ge1 | Should Be $true } } Context 'PS Settings' { It 'can execute scripts' { (Get-ExecutionPolicy) | Should Not Be 'Restricted' } It 'does not use AllSigned' { (Get-ExecutionPolicy) | Should Not Be 'AllSigned' } It 'does not have GPO restrictions' { (Get-ExecutionPolicy-Scope MachinePolicy) | Should Be 'Undefined' (Get-ExecutionPolicy-Scope UserPolicy) | Should Be 'Undefined' } } }
当您运行它时(当然,前提是已经安装了 Pester 模块),这是得到的输出结果:
1 2 3 4 5 6 7 8 9 10 11
Describing PowerShell Basic Check
Context PS Versioning [+] is current version 76ms
Context PS Settings [+] can execute scripts 47ms [+] does not use AllSigned 18ms [+] does not have GPO restrictions 21ms
然而,现在有越来越多的宿主。Visual Studio 可以作为 PowerShell 的宿主,Visual Studio Code 也可以。而且还有许多商业编辑器。所以您需要确定一个脚本是否在一个特定的环境中运行,请使用宿主标识符来代替:
1 2 3 4
$name = $host.Name $inISE = $name-eq'Windows PowerShell ISE Host'
"Running in ISE: $inISE"
Each host emits its own host name, so this approach can be adjusted to any host. When you run a script inside Visual Studio Code, for example, the host name is “Visual Studio Code Host”. 每个宿主会提供它的宿主名称,所以这种方法可以适用于任何宿主。例如当您在 Visual Studio Code 中运行一个脚本,宿主名会变为 “Visual Studio Code Host”。