I don't remember ever being prompted for multiple selections before in PowerShell, but I've seen several examples of hosts implementing this interface. Unfortunately, those are the only references I've seen to the interface. I've never seen "here's how to test that you're implementing it correctly".
Please, disregard my first answer; it is not an answer at all, as I can see now. And thank you for a really interesting question.
I still do not know cmdlets that use that interface. But we can use it on our own from scripts. Let's modify the mentioned Get-Choice.ps1 and call the new one Get-Choice2.ps1:
<#
.SYNOPSIS
Displays PowerShell style menu and gets user choices
.DESCRIPTION
*) Returns choice indexes.
*) Choice keys are indicated by '&' in menu items.
*) Help strings can be empty or nulls (items are used themselves).
#>
param
(
# Menu caption
[string]$Caption = 'Confirm',
# Menu message
[string]$Message = 'Are you sure you want to continue?',
# Choice info pairs: item1, help1, item2, help2, ...
[string[]]$Choices = ('&Yes', 'Continue', '&No', 'Stop'),
# Default choice indexes (i.e. selected on [Enter])
[int[]]$DefaultChoice = #(0)
)
if ($args) { throw "Unknown parameters: $args" }
if ($Choices.Count % 2) { throw "Choice count must be even." }
$descriptions = #()
for($i = 0; $i -lt $Choices.Count; $i += 2) {
$c = [System.Management.Automation.Host.ChoiceDescription]$Choices[$i]
$c.HelpMessage = $Choices[$i + 1]
if (!$c.HelpMessage) {
$c.HelpMessage = $Choices[$i].Replace('&', '')
}
$descriptions += $c
}
$Host.UI.PromptForChoice($Caption, $Message, [System.Management.Automation.Host.ChoiceDescription[]]$descriptions, $DefaultChoice)
Now we test it:
Get-Choice2 'Title' 'Message' -DefaultChoice 0, 1, 2 -Choices #(
'Choice &1', 'This is choice 1'
'Choice &2', ''
'Choice &3', ''
'Choice &4', ''
'Choice &5', ''
'Choice &6', ''
'Choice &7', ''
'Choice &8', ''
'Choice &9', ''
'Choice &0', ''
)
It prints 10 choices, the first 3 are highlighted (in the console host), and prompts:
0> Test-Get-Choice2.ps1
Title
Message
[1] Choice 1
[2] Choice 2
[3] Choice 3
[4] Choice 4
[5] Choice 5
[6] Choice 6
[7] Choice 7
[8] Choice 8
[9] Choice 9
[0] Choice 0
[?] Help
(default choices are 1,2,3)
Choice[0]:
If we press Enter immediately the output is the default 3 indexes: 0, 1, 2. If we type, for example: 5 + Enter + 3 + Enter + 1 + Enter + Enter then the output is 4, 2, 0.
It works. PowerShell ISE also supports this but the UI might be something better in GUI version, perhaps.
For example: the command Remove-Item C:\TEMP\Test prompts you to choose:
Confirm
The item at C:\TEMP\Test has children and the Recurse parameter was not specified. If you continue, all children will be removed with the item. Are you sure you want to continue?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):
Or you can build your own call using this script (or its idea):
Get-Choice.ps1 - Displays PowerShell style menu and gets a user choice
Related
I am trying to process a flag from the MECM command Get-CMTaskSequenceDeployment called 'AdvertFlags'.
The information from Microsoft in relation to this value is HERE
The value returned is designated as : Data type: UInt32
In the table of flags, the one I need to check is listed as :
Hexadecimal (Bit)
Description
0x00000020 (5)
IMMEDIATE. Announce the advertisement to the user immediately.
As part of my Powershell script I am trying to ascertain if this flag is set.
I can see by converting it to Binary that a particular bit gets set.
When the settings is enabled:
DRIVE:\> [convert]::ToString((Get-CMTaskSequenceDeployment -AdvertisementID ABC20723).AdvertFlags, 2)
100110010000000000100000
When the setting is disabled:
DRIVE:\> [convert]::ToString((Get-CMTaskSequenceDeployment -AdvertisementID ABC20723).AdvertFlags, 2)
100110010000000000000000
The 6th bit is changed. Great! So far though, I've been unable to find a way to check if this bit is set. I suspected something in the bitwise operators (-band -bor etc) would help me here but I've been unable to get it to work.
Any bitwise operation I try returns an error:
"System.UInt64". Error: "Value was either too large or too small for a UInt64."
I mean, I can compare the string literally, but other options may be changed at any point.
Any help greatly appreciated.
EDIT: Just as an example of the error I am seeing, I can see that the bit that is set is '32' and from my limited understanding I should be able to:
PS:\> '100110010000000000100000' -band '32'
Cannot convert value "100110010000000000100000" to type "System.UInt64". Error: "Value was either too large or too small for a UInt64."
At line:1 char:1
+ '100110010000000000100000' -band '32'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastIConvertible
But I just always return an error
To test bit6 in
$AdvertFlags = (Get-CMTaskSequenceDeployment -AdvertisementID ABC20723).AdvertFlags
Should simply be:
if ($AdvertFlags -band 32) { 'bit6 is set' } else { 'bit6 is not set' }
I do not have access to a deployment environment with Get-CMTaskSequenceDeployment cmdlet, nevertheless to confirm what I am stating:
$AdvertFlags = [Convert]::ToUInt32("100110010000000000100000", 2)
$AdvertFlags
10027040
if ($AdvertFlags -band 32) { 'bit6 is set' } else { 'bit6 is not set' }
bit6 is set
$AdvertFlags = [Convert]::ToUInt32("100110010000000000000000", 2)
$AdvertFlags
10027008
if ($AdvertFlags -band 32) { 'bit6 is set' } else { 'bit6 is not set' }
bit6 is not set
Your self-answer using [bigint]'100110010000000000100000' -band "32" to test for bit6 is merely a coincident that it returns the expected value:
10027035..10027045 |ForEach-Object {
$Binary = [convert]::ToString($_, 2)
[pscustomobject]#{
Binary = $Binary
bAnd = $_ -bAnd 32
Bigint = [bigint]$Binary -band "32"
}
}
Yields:
Binary bAnd Bigint
------ ---- ------
100110010000000000011011 0 0
100110010000000000011100 0 0
100110010000000000011101 0 0
100110010000000000011110 0 32 # ← incorrect
100110010000000000011111 0 32 # ← incorrect
100110010000000000100000 32 32
100110010000000000100001 32 32
100110010000000000100010 32 32
100110010000000000100011 32 32
100110010000000000100100 32 0 # ← incorrect
100110010000000000100101 32 0 # ← incorrect
enumerations as flags
But PowerShell has an even nicer way to test them by name:
[Flags()] enum AdvertFlags {
IMMEDIATE = 0x00000020 # Announce the advertisement to the user immediately.
ONSYSTEMSTARTUP = 0x00000100 # Announce the advertisement to the user on system startup.
ONUSERLOGON = 0x00000200 # Announce the advertisement to the user on logon.
ONUSERLOGOFF = 0x00000400 # Announce the advertisement to the user on logoff.
OPTIONALPREDOWNLOAD = 0x00001000 # If the selected architecture and language matches that of the client, the package content will be downloaded in advance
WINDOWS_CE = 0x00008000 # The advertisement is for a device client.
ENABLE_PEER_CACHING = 0x00010000 # This information applies to System Center 2012 Configuration Manager SP1 or later, and System Center 2012 R2 Configuration Manager or later.
DONOT_FALLBACK = 0x00020000 # Do not fall back to unprotected distribution points.
ENABLE_TS_FROM_CD_AND_PXE = 0x00040000 # The task sequence is available to removable media and the pre-boot execution environment (PXE) service point.
APTSINTRANETONLY = 0x00080000 #
OVERRIDE_SERVICE_WINDOWS = 0x00100000 # Override maintenance windows in announcing the advertisement to the user.
REBOOT_OUTSIDE_OF_SERVICE_WINDOWS = 0x00200000 # Reboot outside of maintenance windows.
WAKE_ON_LAN_ENABLED = 0x00400000 # Announce the advertisement to the user with Wake On LAN enabled.
SHOW_PROGRESS = 0x00800000 # Announce the advertisement to the user showing task sequence progress.
NO_DISPLAY = 0x02000000 # The user should not run programs independently of the assignment.
ONSLOWNET = 0x04000000 # Assignments are mandatory over a slow network connection.
TARGETTOWINPE = 0x10000000 # Target this deployment to WinPE only.
HIDDENINWINPE = 0x20000000 # Target this deployment to WinPE only but hide in WinPE. It can only be used by TS variable SMSTSPreferredAdvertID.
}
# $AdvertFlags = [AdvertFlags](Get-CMTaskSequenceDeployment -AdvertisementID ABC20723).AdvertFlags
$AdvertFlags = [AdvertFlags][Convert]::ToUInt32("100110010000000000100000", 2)
# or: $AdvertFlags = [AdvertFlags]('IMMEDIATE', 'ENABLE_PEER_CACHING', 'APTSINTRANETONLY', 'OVERRIDE_SERVICE_WINDOWS', 'SHOW_PROGRESS')
$AdvertFlags
IMMEDIATE, ENABLE_PEER_CACHING, APTSINTRANETONLY, OVERRIDE_SERVICE_WINDOWS, SHOW_PROGRESS
$AdvertFlags -bAnd [AdvertFlags]'IMMEDIATE'
IMMEDIATE
EDIT: My answer here is incorrect as noted above. Leaving here for prosperity!
As always I BELEIVE I found the answer minutes after posting (After spending a couple hours on this!).
By adjusting the type to [bigint] the comparison was able to complete and return the expected answer:
DRIVE:\> [bigint]'100110010000000000100000' -band "32"
32
So a simple:
If (([bigint]'100110010000000000100000' -band "32") -gt 0){$true}else{$false}
True
and:
If (([bigint]'100110010000000000000000' -band "32") -gt 0){$true}else{$false}
False
Solves my issue. Feel free to give any extra advice if this is not the ideal way to proceed.
I though PS would be smarted when auto defining types etc. This is targeting PS5 on Server 2012 R2 though.
I want to translate this AutoIt script to Powershell v2.
(AutoIt is a freeware BASIC-like scripting https://www.autoitscript.com/site/autoit/downloads/ )
#include <WinAPIGdi.au3>
Local $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & #ComputerName & "\root\cimv2")
Local $colMonitors = $objWMIService.ExecQuery ("Select * from Win32_DesktopMonitor Where Availability=3", "WQL", 0x10 + 0x20)
If NOT IsObj($colMonitors) Then Exit
Local $iCount = 0
For $oMonitor In $colMonitors
$iCount += 1
Next
MsgBox(0, "", "Number of monitors : " & $iCount)
$aMonitor = _WinAPI_EnumDisplayMonitors()
If #error Then Exit
ConsoleWrite ("!! multiscreen mode:" & $aMonitor[0][0]) ;value equal one if there is one screen duplicated or not, if extended the value wille be greater than one. I don’t mind if the computer screen are powered on or not.
If $aMonitor[0][0] > 1 Then
MsgBox(0, "", "extended mode"&$aMonitor[0][0] ) ;give 2
Else
MsgBox(0, "", "duplicate mode"&$aMonitor[0][0] ) ;give 1
EndIf
;---Excerpt from WinAPIGdi.au3 (included with AutoIt) :---
Func _WinAPI_EnumDisplayMonitors($hDC = 0, $tRECT = 0)
Local $hEnumProc = DllCallbackRegister('__EnumDisplayMonitorsProc', 'bool', 'handle;handle;ptr;lparam')
Dim $__g_vEnum[101][2] = [[0]]
Local $aRet = DllCall('user32.dll', 'bool', 'EnumDisplayMonitors', 'handle', $hDC, 'struct*', $tRECT, _
'ptr', DllCallbackGetPtr($hEnumProc), 'lparam', 0)
If #error Or Not $aRet[0] Or Not $__g_vEnum[0][0] Then
$__g_vEnum = #error + 10
EndIf
DllCallbackFree($hEnumProc)
If $__g_vEnum Then Return SetError($__g_vEnum, 0, 0)
__Inc($__g_vEnum, -1)
Return $__g_vEnum
EndFunc ;==>_WinAPI_EnumDisplayMonitors
I tried to begin with this commands in Powershell:
Get-Wmiobject win32_DesktopMonitor |format-list
Get-Wmiobject -query "select Name,DeviceID,DisplayType from win32_DesktopMonitor where Availability=3"
It works but it’s really too short...
Can you please specify what you would like to do? I am not sure what you are trying to achieve.
It works but it’s really too short...
So it works. That's good - right?
If you want to check how many screens are connected you can use the following cmdlet:
Get-CimInstance -Namespace root\wmi -ClassName WmiMonitorBasicDisplayParams
Source: Use PowerShell to Discover Multi-Monitor Information
I'm coding a ISPF Panel with "Point and shoot" elements. The elements say "yes" and "no" and the default cursor have to point to "yes".
1st Case:
Declaration of the fields: + TYPE(INPUT) PAS(ON)
When I use this declaration, the panel closes by pressing [enter] and generating rc = 0. However, the )PNTS section doesn't run.
2nd CASE:
Declaration of the fields: + TYPE (PS)
The )PNTS section runs by pressing [enter]. However, I cannot set the .cursor to the field "yes".
I tryed different ways with different field names (e.g. ZPS00001). I tryed to simulate Point and Shoot with Rexx, but nothing worked really fine.
Pressing enter will cause the point and shoot fields to be processed. However the cursor must be on one of the fields for the )PNTS section to set the value associated with a field. It would sound like panel may have not been coded correctly. PAS should be used for input or output fields and PS should be used for text fields. For instance if you have the following panel:
)ATTR
$ TYPE(PS)
! TYPE(OUTPUT) PAS(ON)
)BODY
+ --------------------- +
+ ===>_ZCMD +
+
$Field1 : _FLD +
$Field2 : _ABC +
$Field3 : !IN1 +
$Field4 : !IN2 +
)INIT
&INV1 = 111
&INV2 = 222
&INV3 = 333
)REINIT
REFRESH(*)
)PROC
)PNTS
FIELD(IN1) VAR(INV1) VAL(ON)
FIELD(IN2) VAR(INV2) VAL(OFF)
FIELD(ZPS00001) VAR(INV3) VAL(1)
FIELD(ZPS00002) VAR(INV3) VAL(2)
FIELD(ZPS00003) VAR(INV3) VAL(3)
FIELD(ZPS00004) VAR(INV3) VAL(4)
)END
With the following REXX exec:
/* REXX */
RCC = 0
INV1 = 0
INV2 = 1
DO WHILE RCC = 0
ADDRESS ISPEXEC 'DISPLAY PANEL(PAS)'
RCC = RC
SAY INV1 '-' INV2 '-' INV3
END
You can test the values of inv1, inv2 and inv3 based on where you put the cursor when you hit enter. You will get 1, 2, 3 or 4 if the cursor in on field1, field2, field3 or field4. If it is on IN1 or IN2 then you get ON or OFF. It all depends on where the cursor is positioned when ENTER is hit. Based on the example you can see point and shoot is not limited to Menus. Hope the example helps.
Marv Knight
As C# does not has the options of powershell's write-progress I start to try to 're-use' the same line:
function ReUseFails {
$x=0
$nDec = 10
while ($true) {
$x++
$a = $x.ToString().PadLeft($nDec)
$z = $x.ToString().PadLeft($nDec)
Write-Host "`r$a $z" -noNewLine
Start-Sleep -s 1
}
}
ReUseFails
I expected because of `r (carriage return) to see in the same line (the next line overrides the prev.):
1 1 # and after 1 Second in that line:
2 2 # after the 2nd second
3 3 # (and so on)
but what I get is
1 1 2 2 3 3 4 4 ...
So the carriage return r has no effect?<br>
Is there a way to 'enable' thisr??
Even when I try to use `b I see additional spots but not a back-space.
Can it be that the DOS-console can do that (to show a spinning wheel) but bot the PS-console?
Regards
I am quite an expert when it comes to programming in the MSL language, however I am unfamiliar with raw commands and whatnot.
I am in development of a new script. In this script I would like to check if $4 in what a user says is a registered nick or not but I do not know how to do this.
Thank you very much for any help and/or advice in advanced.
Best Regards,
Tim
Update:
raw 307:*:{ set $+(%,%chan,-,%CheckNick) Registered }
on *:TEXT:*:#:{
if ($1 == !regtest) {
set %chan $remove($chan,$chr(35))
set %CheckNick $4
whois $4
}
if ($($+(%,%chan,-,%CheckNick),$4),5) != $null) {
do this...
}
else {
else message...
}
}
I got this to work to check however my if statement to check if the variable has been set or not is being ignored...
Edit:
I tried using this:
checkNickReg $chan $2 $nick
...And echoing this:
echo -a Target: $1
echo -a Nick: $2
echo -a Status: $3
echo -a Chan: $3 - $chan
I'm trying to get a response to the channel such as; $nick $+ , $1 is not registered/registered/registered but not logged in.
What I've posted above is obviously wrong as it doesn't work, however I've tried a few methods and I'm actually not sure how the data is passed on with out the likes of tokenizing or setting variables...
Reply
[01:59:06] <~MrTIMarshall> !isReged mr-dynomite
[01:59:08] <&TornHQ> : mr-dynomite status is: NOTLOGGED
EDIT: mr-dynomite is not currently on, should this not = does not exist or does this check even when their not on, if so this is bloody brillant!!!
[02:00:04] <~MrTIMarshall> !isReged MrTIMarshall
[02:00:04] <&TornHQ> : MrTIMarshall status is: LOGGEDIN
$4 does not seem to work and what is the difference between 'exists, not logged in' and 'recognized, not logged in'?
Also, how does the data get passed on without setting variables or tokenizing?
(P.S. Thank you so much for the help you have dedicated so far!)
Another Edit:
I've been taking an in depth look today, am I correct in thinking if 0 or 1 the user is either not on-line or not registered (in the comments it says 0 = does not exists / not online, 1 = not logged in whereas 2 also says not logged in but recognized of which I'm unsure as what recognized means. Otherwise I'm very grateful for this script help and whatnot I'm just unclear on the numbers...
Since you have not specified any particular network I wrote an outline for some common networks around (that actually have user authentication systems). You should be able to add many other networks following the pattern.
Basically you execute /checkNickReg <target> <nick> [optional extra data] and when the server replays with the registration info (if applicable) use the on isReged signal event to handle the reply. Everything else is pretty much transparent.
EDIT: Looks like the specified network you are using (Torn) uses the standard anope services. So I updated the code to support that network.
; triggers when you get nick registration info back
; $1 = Target
; $2 = Nick
; $3 = Status, can be: LOGGEDIN, RECOGNIZED, NOTLOGGED
; $4- = Everything else passed
on *:signal:isReged:{
echo -a Target: $1
echo -a Nick: $2
echo -a Status: $3
echo -a Else: $4-
}
; reg lookup routines
alias checkNickReg {
set %reg. $+ $network 1
set %reg.target. $+ $network $1
set %reg.nick. $+ $network $2
set %reg.other. $+ $network $3-
; Freenode uses: NickServ ACC <nick>
if ($network == Freenode) msg NickServ ACC $2
; Rizon/SwiftIRC/OFTC/Torn use: NickServ STATUS <nick>
elseif ($istok(Rizon SwiftIRC OFTC Torn, $network, 32)) msg NickServ STATUS $2
}
; listen for replays
on *:notice:*:*:{
if ($($+(%, reg., $network),2)) {
;
var %target = $($+(%, reg.target., $network),2)
var %nick = $($+(%, reg.nick., $network),2)
var %other = $($+(%, reg.other., $network),2)
;
unset %reg*. $+ $network
if (($network == FreeNode) && ($2 == ACC)) $&
|| (($istok(Rizon SwiftIRC OFTC Torn, $network, 32)) && ($1 == STATUS)) {
; FreeNode:
; 0 = does not exist
; 1 = exists, not logged in
; 2 = recognized, not logged in
; 3 = logged in
; Rizon/SwiftIRC/OFTC/Torn:
; 0 = does not exists / not online
; 1 = not logged in
; 2 = recognized, not logged in
; 3 = logged in
if ($3 < 2) var %status = NOTLOGGED
elseif ($3 == 2) var %status = RECOGNIZED
else var %status = LOGGEDIN
}
;send status signal
.signal isReged %target %nick %status %other
}
}
(Extra Note: It might be useful to add an extra check to make sure $nick is AuthServ/NickServ for security reasons.)
A simple usage example is:
; Just a basic example of how to call it.
on *:text:!isReged &:#:{
checkNickReg $chan $2 $nick
}
on *:signal:isReged:{
msg $1 $4: $2 status is: $3
}
Type !isReged <nick>
Edit: The data gets passed to the on isReged event via global variables. I set them in the checkNickReg alias and I clean them up in the on notice event. So you never see them because they get cleaned up. They are passed to the isReged signal event in $1-.
On most IRCDs, it's only exposed in the WHOIS response for a user, if at all. Running a WHOIS every time a user says something is inadvisable, especially because server admins may receive a notification every time it happens.