PowerShell и GUI. Это — не сложно
Некоторое время назад в компании была развернута терминальная ферма.
Первым делом в неё были выселены пользователи некой желтой программы.
После чего отдел поддержки желтой программы спросил меня, можно ли отсылать сообщения пользователям фермы всем сразу. XaocCPS посоветовал мне играться в сторону WPF. Нужный скрипт был написан, но его работой я неудовлетворился:
1. Надо ставить внешний компонент PowerShellPack.
2. Компонент ставиться на сервера фермы (х64) отказался.
3. Распространять такое решение из за пункта 1 всем желающим не очень удобно.
Xaegr подсказал что я могу избавиться от прослойки WPF.
Писать можно, можно даже писать красиво. Скрипт выполняется везде где есть .Net Framework — XP, Win7 и скорее всего пойдет даже на х64 серверах фермы.
Как писать — под катом.
UPD по просьбам скрипт выложен на SkyDrive, ссылка в конце
И так — ТЗ, полученное от отдела поддержки было «отправка сообщений всем пользователям терминальной фермы».
Мною ТЗ было расширено:
1. Выбор серверов.
2. Выбор пользователей.
3. Ввод текста сообщения.
4. Вставка подписи — идентификатор отправившего сообщения пользователя — виден в заголовке окна, но на него внимание обращают мало, выбрал вариант из нескольких предустановленных вариантов.
5. Защита от нечаянной отправки.
Предварительно было найдено, что в Win7 и 2008* есть команда msg, с помощью которой данные сообщения и будут отправляться, но прием сообщений надо разрешить, что и сделал простеньким regedit файлом:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server]
«AllowRemoteRPC»=dword:00000001
К сожалению, если пользователь из списка не подключен к серверу — скрипт много и сильно ругается. Я пока не придумал как получить вывод msg, и его обрабатывать.
Скрипт по максимуму комментирован.
В результате получилась вот такая вот красивость
Скрипт могу выложить, при желании читателей, куда-то.
Не уверен, что хватит кармы публировать в профильный, поэтому выложил сюда
Powershell windows forms textbox
Вопрос
I am struggling with a form, in combination with a Textbox and data entered into it. I started to build a test script that works as shown in example 1 and then extended it and need to do some minor changes to make it work.
In example 1: I generate a Form, ask for a Name and after a data input and pressing OK, a second form opens to present the data in a label. That works fine and I would like to have it on such way.
I have extended this form and because I have several Textboxes, I wanted to have a mechanism, to prevent a textbox left-out without any data entered.
In example 2 you can see how the code looks slightly different.
The ClickEvent (thanx jrv) checks if data has been entered and if not, will give a warning. This also works perfectly and I was happy but then, I faced a new problem:
As soon as the second form opens, for some reason, the content of the textbox in the example called «$TestFormTextBoxFirstname.text» is empty.
What I was able to find out is, that if I run the Script a second time, I get the UserInput from the first try and if I understand correctly, that means, that the name entered in example 2 and stored as a variable, runs through without being forwarding to the second form to «$ConfirmationNamevar.text». I was playing around, trying different approaches but was not able to fix it.
I tried this approach, because I had no clue, how to show «$TestFormTextBoxFirstname.text» directly in the Label. Here, I also tried several ways but failed also.
What am I doing wrong? Can someone help with a solution, so I can keep the ClickEvent and have the content of the Textbox transferred into the Second Form, so the name is shown, as it works correctly in example 1?
Thank you very much for your help,
Ответы
Warning: Setting everything to global is NOT an acceptable programming solution.
Here is a place to start if you really want to learn PowerShell and how to write code:
- Предложено в качестве ответа LeeSeenLi Microsoft contingent staff 25 февраля 2019 г. 7:37
- Помечено в качестве ответа mstgier 28 февраля 2019 г. 13:41
My problem was related to the «Global» issue, meaning, that when I tried to forward a variable to another function, I didn’t see them.
Therefore I had to change the variable and put:
But there is also to say, as mentioned by the Expert jrv, that it is not a solution, to set everything to Global and therefore should be used carefully.
thank you very much,
Все ответы
As I noted before, you cannot «hide» a dialog, Hiding it destroys the form.
Hint: Make your forms functions. Call the second form function from the first form but do not hide the first form. Pass the information as a Param() statement.
I by mistake did not send the last message, so let me do it again.
That with hiding or closing the form is no problem and I can keep it open. I also had a quick look into Param today but then went back into trying to solve the issue. I will have a look into Param and hopefully will be able to solve it on such way.
Thanx again for your great support, I really do learn a lot through you and your tips and help.
Greetings from Europe,
Just to get you going in the right direction this is how to build a form with less pain.
Pain it is, but I think we learn from pain (at least I do).
Thanx a lot, I will run tests and read about Param and hopefully will find my way, otherwise you will read me 😉
I will stick to your hint,
«Hiding» a form while it is showing a child form will eventually cause you more headaches.
I am testing the param and must say, it is really a great thing to have. And I do fully believe you, that a form in combination with a child form and hiding is a pain.
Nevertheless, I am still facing a problem and would like to ask for your help.
I changed the script as I think is correct but there is still something not working.
Here is my script:
The problem is, that at the end, as soon as I call «Show-ConfirmationForm -FirstName $TestFormTextBoxFirstname.Text», the code does not continue. I also tried to first hide or close the «$testform» but that of course did not help.
What I do not understand is, that with previous tests, I was able to open a new form without any problems and as soon as I replace $yyy.ShowDialog() with Show-ConfirmationForm, it does not work anymore.
I assume, you know why.
It is important to me, that I can keep the clickEvent with the IF order, to catch textboxes, which are forgotten to be filled out.
How can I fix this behaviour? I am sure, you have a solution up your sleeve.
Thank you very much,
That is correct. The second form will always freeze everything else until it clicks. This is how dialogs work. You do not have a main from and a child form. You have a dialog showing a dialog. PowerShell does not have the ability to show a form. It can only show dialogs.
To get independent forms you must use runspaces.
I understand and have also no problem with it. The Mainform is to fill out user information. The child form is used to check, if the information entered was correct (to give the user a chance to see typos) and as soon as it is good, the child form shall create a user in AD with the input from the Mainform. So if the Childform is freezing the mainform, that has no influence but what I do not understand is, why am I not able to call the function? Is the function blocked through the mainform?
Reading about runspaces now
What function? What is the error?
It is actually the last test script I have copied around 30 Minutes ago.
It opens the first form and asks for a name to be entered. It checks, if anything has been entered and if not, there is a message telling you, that nothing has been entered.
As soon as you have filled in a name and you press the OK button, I wanted to call the function and do not get any error at all. I just see my first form and the second form does not open. Something is blocking and I have no clue, what to do, to call the function «Show-ConfirmationForm -Firstname $TestFormTextBoxFirstname.Text»
Maybe, I misunderstood you but I thought, that when I have the child form in a function, I should be able to call that function from the first form, check if everything is OK and then press also a button and then the child form can be closed, is no further needed.
but I am not able to call the function, I only see the first form and am stuck there.
You logic is wrong. I posted the correct test logic but you have changed it back. You also have both forms in one function which is not what I suggested. Each form has to be a separate function. No form code can exist outside of that forms function.
hmmm ok. I tried to adjust the example you sent, to forward the name entered to the second form, that is why I did that.
If I splitt the forms into individual functions, would I still face the same problem? I assume yes (that is where my logic stops to work), because I still would try to open a second form and powershell does not like that, correct?
So in that case, my only chance is with runspaces?
This is the form and how to create and use it. You just reused your old and very badly written code without understanding why I made changes to it.
TO simplify your coding stop using long variable names. Inside a form function in makes no sense to name every variable with the form name. Just use a name that represents the data and the control type.
The form in the function should just be named $form.
Don’t use System.Drawing. It is unnecessary. Remove it from your code.
Once you simplify your code you will find it easier to understand.
Learning forms can be a challenge for a non-programmer. Slow down and try to understand how to use basic programming. You also need to learn basic PowerShell as most of what I see says you have learned by copying what other untrained users have written or by pure guesswork.
Windows is a very complex but highly predictable technical system. Windows is an object system. PowerShell is an object management system. They work well together.
Windows forms are also an asynchronous event driven object system. You need to understand how forms are driven by events.
Also learn logic and logic expression.
The following code is wrong and shows you don’t understand what an event scriptblock is.
It is incorrect syntax and is badly formatted. The logic is also faulty.
If formatted better the issues start to show up:
The parens around the script block are not needed and can cause issues. Also use positive logic whenever possible. Never test a Boolean agains a string. It will always fail.
PS D:\scripts> $true -eq ‘FALSE’
True
A Boolean only needs to be tested. There is no need to compare it. It is either true or false. In PowerShell and empty variable will always test $false. No need to do more than the following.
Now the script bit is cleaner and easier to understand. With logic switches or control-flow statements we almost always want the main path to be first and the negative path to second. This is referred to as positive logic. It is easier to build and easier to read and understand.
Fix the above and your code will begin to work although you will find that building forms on a hi-res monitor will create forms unusable on standard monitors. Setting up a form for compatibility will take some more effort.
- Предложено в качестве ответа LeeSeenLi Microsoft contingent staff 28 февраля 2019 г. 9:50
hmmm ok. I tried to adjust the example you sent, to forward the name entered to the second form, that is why I did that.
If I splitt the forms into individual functions, would I still face the same problem? I assume yes (that is where my logic stops to work), because I still would try to open a second form and powershell does not like that, correct?
So in that case, my only chance is with runspaces?
No. You first need to understand how your code is failing and why. Right now you are just making one bad guess after another. You have launched into PowerShell and form building with no background in how these things work and are used. You need to slow down and try to understand what the code does and how. We cannot do that for you. It is part of the learning process for any complex technology.
You are right. Unfortunately, I have no clue about coding and also regret it, that I haven’t started it 20 years ago.
I see a great potential in PowerShell and also see how it can be implemented and help IT administrators. I have worked in IT for a long time but never had to code.
It is difficult to see and understand, what code is good found on the net and what is bad. Yes, starting from scratch is something I have to do and I try to understand through the mistakes but it looks like, that Forms is more complicated then it seems at the first moment. Building the form itself is not that difficult and I also faced the issue with resolution, where suddenly the form looks differently.
It seems to be very obvious, that I have no background and I hope you did not pull out all your hair. I know, it can be frustrated around people, that have no clue about technology, I have that on a daily basis but in a different form.
I will step back and take it slower and hopefully will be able to learn and have a better understanding.
thanx for the help as always,
You need to understand that you are taking on a very long a steep learning curve. Start small. First things first. Learn PowerShell to a level of competency. That will help you recognize bad code. Read the technical documentation o PowerShell and Windows Forms.
Fully understand jrv. I know, I have no clue about coding but had the intention to do something good but realised, that powershell runs through and doesn’t allow me to jump around like with Basic in the early times. I have started building a GUI and then wanted to have my checks and functions but now I realised, nope, that is not how you do it, so I will start slowly.
Thank you so much for all the pain you went through 😉 and for the help and the links. Step by Step as you said,
Also note that the validation code should be in the controls «Validating» event. This gives the best user feedback and requires less code. We can also use the ErrorProvider control to flag the control with an error icon and popup message telling the user what is expected. This would eliminate a large amount of convoluted logic.
As a starter you should read the forms documentation to get oriented. It will make designing forms much easier.
Also there are tools that build PowerShell forms. There are a number of web sites that will generate forms code for free and there are editors that can do much more. There are two that are exceptional. Sapien PowerShell Studio and one as an add-in to VSCode.
Microsoft did not design the Windows API or the Net Forms classes for end users. They were designed for programmers and specifically enterprise programmers who build large numbers of very complex data entry forms. The history of forms comes from the IBM CUA specifications but has evolved dramatically due to the advent of the GUI.
The design of the forms system is intended too automate all CUA and later standards for user access to data entry and to allow programmers to easily implement all of the standards easily. There is only one way to learn forms and that is from the ground up. Most PS users kluge things together and end up writing 10 times as much code then is needed. If you need to do it in a form then there is likely an event, property or method that does that. Also knowing which controls to use is critical to a form design. An all of this i before we even write a single line of code.
Luckily almost al forms are built and generated using forms designers and code generators. Hand coding forms went out with the fist version of Visual Studio. Visual C was good but still required writing raw API code. MFC forms were better but required do much of the wiring by typing. The Net Framework standardized the control hierarchy and added better event routing which greatly simplified coding. MS tested VS forms code against all other tools and methods and found a 200+ increase in coding speed as well as something like 100 times less code to do any complex job in VS 2000.
Sapien has the best IDE for Forms. The VSCode add-in does WPF forms and is still evolving.
My take is that Admins and techs should not try to build applications because they have no formal developer training and will generate unsafe and unmanageable code. Admins and techs can learn basic forms and create simple tools for administration and troubleshooting as long as the tools are for limited use by others trained in the technology the tool attempts to address.
Here is a link to some forms code that may not be useful but the project can show you how code can be used to create a very complex form with sub forms with very little code:
There are three articles on Forms. Unfortunately BlogSpot keeps screwing with their site and the examples keep getting damaged. The downloads should still work. The full PS1 demo file is pretty snazzy for a simple demo and demonstrates interesting techniques for editing data in a form.
Post back if the downloads are not working.