Powershell and the Windows Taskbar

I recently had the need to replace our current background changer to something more robust and something I could tweak the code on. In doing my research I found that Powershell would work nicely as a script for my users when they logon.

Having done an extensive amount of programming work in many different languages I figured this would be a piece of cake. I’m not here to bash PS as its certainly a pretty cool tool for scripting. No I’m here to drop off a nugget of code that I found myself needing but my Google prowess could not locate in a nice and neat package.

So here you go. A simple class to get the information you want about the task bar. Location, height and width, and even what screen it’s on if you have multiple screens.

 

RealVNC

I have used RealVNC in our organization for many years and the other day I was kind of bored and decided to make an app that would tell me which PC’s had it installed and was it listening for the viewer.

My situation is this: User calls or sends in support request, I open up a log file looking for the users IP or machine name, enter it in the vnc viewer and try to connect. I wanted a faster, easier way to do this with less steps.

For this I would read in the log files for the user logons, then test each PC the user was last logged onto to see if it had vnc listening on port 5900. Easy enough.

For those interested first you will need to setup a logon script, here is mine:

I have this script along with the logoff script in the DC NETLOGON share.

In Group Policy I use the User Configuration\Policies\Windows Settings\Scripts\Logon and logoff settings to specify my script location. Now each time the user logs off and on it makes an entry in their corresponding log.

Here is the logoff script, its the same except “logon” is replaced with “logoff”:

So that gives me the file I need for the next step which is loading the list with the following:

This function calls GetUsers to load the list of users that we currently have log files for and then if we are checking for a vnc connection call TestSelectedPort and set the image for the list view item appropriately.

Here is the project zipped for you with all the code.

Remote Project

Once the application is run you are first presented with a static list of the users PC’s. Depending on what view you choose it will either be a picture of a pc with machine name of if you choose details then you will see a list showing the user, pc name, last logon and the ip.

I blocked out the username for security reasons, but you get the idea.

If we click the Check VNC button this is what you end with showing which PC’s are up and running VNC.

Go ahead and download the file and give it a try.

Accessing and modifying user settings between applications in VB.Net

Recently and for the first time I coded a Windows service. A basic service that runs in the background and based upon a set interval would poll all the PC’s and servers on my network looking for archived event logs. I set my logs to save when they reach 16mb. On some boxes due to the amount of auditing I do this was consuming hard drive space pretty rapidly and I needed a simple way to retrieve those logs, zip them up and move them to a folder that gets backed up to the cloud weekly.

Of course as I progressed my service needed some “Settings”. For example the time interval I mentioned, the folder to move the zipped files to, etc. I thought no big deal, I have some canned code with a property grid already setup I will just copy and paste then I can run my service from the command line with a switch to show the dialog. Yea figured out that won’t work. Since its my first service I am learning about the do’s, dont’s and the “that’s not happening” issues. The latter being my problem. Seems like you can’t just run a service from the command line like I thought.

Okay no big deal I will just code a small project just for editing those settings in my service. There it was again, my naivety . I did some research on the web, tried a few suggestions here and there with no luck. Then I landed on a page that someone obviously smarter than I told the group you cannot access other project user settings with vb.net. He went on to explain that the project stores the user settings in some folder with a unique hash and that it was impossible to use.

Huh, sounds like a challenge.

Well first what he said did not make sense. Of the nearly 100 projects I have coded through the years, the projects settings file is in the same folder as the EXE itself. To confirm that my service was using the settings file within its running folder I made some changes in the settings file with notepad and restarted my service. Yup using event viewer I could see my service was in fact using that file. But why? If indeed the the settings were constructed in the project settings as having a scope of “user” then that file would have to be unique for anyone that logs onto that machine, right? Well I went on to investigate some more and his explanation seems to hold water but only for Windows Forms applications and not a service application. User settings are stored in something like this: “C:\Users\gutauckis.CITYOFHOLLYHILL\AppData\Local\Hewlett-Packard Company\Settings\1.0.0.0” and a service is not “user” based. So those settings would not be stored with a user but in the applications directory.

Here is a link to a good explanation the settings architecture 

In his explanation he mentioned just storing your settings in an XML file that both of the projects would know where they are stored. Then you can use one project, the GUI to modify the settings and the service would read them at startup or during code execution. That sounds like a good idea. Since my settings file is stored with the service application and my setting gui will be in the same folder I can just read the settings file, make changes and save it back out.

Here is the code for reading and writing the settings xml file:

To use it:

That’s pretty much it. Nothing fancy. Looking at the xml reader I could probably clean it up, but its working so I will leave it alone for now.

Remember this is for a service application, not a windows forms application. You could do the same thing only you will need to know where the users application setting is stored and share that with your setting GUI application.

Run your forms app and get the Application.LocalUserAppDataPath Property. Then add that to your settings GUI app so it knows where to look. Easy enough.

Those pesky passwords

“The security expert who wrote widely accepted advice in 2003 about online passwords—use special characters and change the passwords regularly—now acknowledges that he misfired. “Much of what I did I now regret,” Bill Burr, who is 72 and retired from the National Institute of Standards and Technology, tells the Wall Street Journal.”

To those not in the know, this isn’t really anything new to us in the technology world. What makes this news is that the man who created our current “standard” is now admitting he got it wrong.

For years many security experts suggested using pass “phrases” instead of some weird conglomeration of upper case, lower case, number and special characters.

Take this for example, let’s say your password was soemthing like DMichael96, according to https://howsecureismypassword.net/ it would only take 8 months to crack that one wide open. But if we used “themanonthemooniswalkingoncheese” it would take 2 octillion years. That’s right, a 2 with 27 zeros after it or 10 to the 27th power.
Besides remembering a phrase like that is much easier to remember than some convoluted password like “5J4kRZqPYT5x”

Now we just have to wait for developers to change the way we log in. As it stands many websites limit the number of characters you may enter for a password. I even have one system where the OS allows you to set the password length to what you want but the field where you enter your password only allows for 8 characters. Weird.

In the meantime I recommend you don’t use your kids initials and their birth date or your dogs name, instead use strong passwords and a password manager to help you manage all of these passwords. I personally use LastPass. I have hundreds of passwords, there is no way I could remember them all.

Using a password manager helps you with using a different password with each site you log on to. This makes your online life much more secure. Most people don’t think much about it but if you use the same password and a hacker hacks that book of the month club you belong to, they now can, quite quickly attempt to log into every bank and credit card company in the world and get into your account.

Visit https://howsecureismypassword.net/ to test your password. You will be surprised by the results.

Sharing printers with Group Policy




I recently had the need to move all of my managed printers from one server to another. I did the normal export printers from the old server and import on the new. Nothing to note except I had one printer that wouldn’t come over. Not sure why, but I figured no big deal I would just recreate it on the new box.

After some testing I changed everyone over to the new printer GP’s. No complaints except from the Org Unit whose printer would not come over. Even though I reinstalled, created and applied the GP it would not work for nothing. I ran the usual tools, RSOP, GPRESULT nothing showed any errors. Ran the modeling wizard in GP management on the Org and got a cryptic error on the Computer and User Component Status about the deployed printers connection. Basically just said there were many errors and to look at the Application Event Log on the domains I ran the model on. Checked both DC’s and there were NO errors. Thanks MS what a big help.

It wasn’t until I ran across an article while troubleshooting about GP Preferences. I stated playing with this and got to the Printer preferences. I went to add the offending printer but discovered it wasn’t listed in Active Directory. Ah Ha!

When back to my Print Server right clicked the printer to “List in Directory” but the option wasn’t there. Say whaaaat? Huh?

I uninstalled and re-installed the printer, but I never got the option to “List in Directory”. Did not make sense as there were many other printers, same model, make, etc and they had the option.

Then it dawned on me… What a dumb ass.

Uninstalled printer, re-installed but this time did NOT uncheck “Share”. The rest… well is history.

RPG Primer for the AS400

hello-world-1333103_640

I have been programming for nearly 30 years now. I started with BASIC on a Texas Instruments TI-99 with voice Synthesizer. https://en.wikipedia.org/wiki/Texas_Instruments_TI-99/4A
I followed that up with my very own Commodore 64 where I continued to dabble in the fine art of coding. Mostly though I spent a lot of time on line on a 300 baud modem. Oh those were the days.
Over the years I have dabbled in many different languages, but Visual Basic.NET and C# have always been my go to languages of choice when programming for the PC.
My issue is that those languages do not work with IBM on their OS400 platform. No there if you want to make this box do anything you have to learn a new language, RPG. On a few occasions in the past I looked into it and because a lack of a good simple Hello World tutorial I gave up. That is until now.
This time I had an actual need to make this box backup some files, then transfer them to the PC with FTP for backing up to the cloud. Sounds simple enough. That is if you know how to program in RPG and how to use the editor and compiler on the OS400. I did not.
Having used the AS400 and its OS for about 18 years I was familiar with getting around the box, so that helps. If this is your first time even looking at a green screen then good luck. This tutorial will get you through to a finished product but it will be a bit daunting for you. Oh lest I forget, if you screw something up while following these directions it’s on you. If you don’t know what you are doing then get someone who does. I take no responsibility for what happens and I don’t guarantee this will work for your situation.

Hello World!
First you must be using IBM i Release 7.3, Release 7.2 TR3, or Release 7.1 TR11. RDi Release 9.5.
This is because I am using the fully free form of coding. It’s much better than what was required before and is easier for programmers of other languages to use.
I began my search on Google, looking for help on programming the AS400. I came across a few books, but when I looked they really looked like they were for someone who already had programming experience on the AS400. I decided to save my money for now and continued my search. Then I came across the aforementioned IBM link. Viola! Hello World! I read through the first page a few times and realized this might work, but the directions where confusing and really incomplete.
For clarification lets go over the steps to create your first program for the AS400.
As an example we want to create a BACKUPPGM program in a library called BACKUP.
Logon to a session on your IBM AS400

Create a library using the CRTLIB command. If you already have a library you want to use then skip this step and substitute your library name in place of the one I used (BACKUP)
1

Next create a Physical File using the CRTSRCPF. Here I name my file BACKUPPF and put it in the BACKUP library I just created.

2

Now we are going to create a member using PDM. Enter WRKMBRPDM on the command line and press F4.

3

Enter the info as you see it above and press enter. You will see the resulting screen.

4

Press F6 to Create a member

5

Enter HELLO for the Source Member, RPGLE for the Source type and give it a description. Press enter when you are done. It will take you to an editor where now you can add your code.
Now let’s write a simple Hello World program
On the first line and it must be the first line of your code enter:
**FREE
This indicates we are using the free form version of code.
Next put the following:
dsply ‘Hello World’;
return;

This is what is going to flash the Hello World on the screen.
When finished you should see something like this:

6

Now press F3 to get out of the editor and accept the defaults for saving the member.
Once back to the member list, you will see your HELLO member. Put a 14 next to it to compile it. Once compiled, from a command line enter: CALL BACKUP/HELLO
Congratulations, you created your first program on the AS400.
Now take it a step further and create that program for backing up some libraries.
We already have our library ( BACKUP) and our Physical File (BACKUPPF) so all we need to do now is create a new member for the backup program.
If you are not already there get back to your member list. (Enter WRKMBRPDM on the command line and press F4.)
Press F6 to create a new member and this time enter BACKUPPGM for the Source Member and RPGLE for the Source Type. Give it a description.
Once again you are back to your editor.
Here we are concerned with three commands:
CRTSAVF – This creates a Save File. This would be the file you want to save your library to.
CLRSAVF – This clears the save file if it contains any data already.
SAVLIB – Saves the specified library to the save file we created earlier.

Now technically you can simply issue the CRTSAVF from the command line and be done with it. This is because after the first time you run your program the save files will have already been created. However for clarity and simplicity I will leave them in the program.
For our example here we want to back up two libraries named HTEDTA and HTEPGM. To do this you would enter the following lines of code in your editor:
**FREE
CRTSAVF FILE(BACKUP/HTEDTA)
CRTSAVF FILE(BACKUP/HTEPGM)
CLRSAVF FILE(BACKUP/HTEDTA)
CLRSAVF FILE(BACKUP/HTEPGM)
SAVLIB LIB(HTEDTA) DEV(*SAVF) SAVF(BACKUP/HTEDTA)
SAVLIB LIB(HTEPGM) DEV(*SAVF) SAVF(BACKUP/HTEPGM)
Now let me break it down for you.
CRTSAVF FILE(BACKUP/HTEDTA)
This creates a save file in the library BACKUP we created earlier called HTEDTA.
CLRSAVF FILE(BACKUP/HTEDTA)
This clears the save file in the library BACKUP called HTEDTA.
SAVLIB LIB(HTEDTA) DEV(*SAVF) SAVF(BACKUP/ HTEDTA)
This saves the library called HTEDTA using the device Save File to the save file called HTEDTA in the library BACKUP.
Now that you have entered all your code press F3 and save your source member.
Put a 14 next to it and compile.
To run it you can enter on the command line CALL BACKUP/ BACKUPPGM
This will now save the libraries you specified to the save files you created. From here we can now go to a PC and FTP the files down.
Open your favorite desktop file editor and enter the following:
OPEN

bin
prompt
cd BACKUP
mget *
quit
Note: It is a good idea to use a AS400 user that only has read access to the box as you are storing these options in clear text on a PC.
Save the file as ftp_options.txt
Now create a Batch file and add this to it:
ftp –s:ftp_options.txt
Save the batch file in the same folder as the ftp_options.txt file.
Now you can use this batch file manually by running for a command line or as part of the command in Task Scheduler.
My intent here was to combine learning to program the AS400 and backing up to the PC while adding some clarity for the new AS400 programmer.
I want to thank Drew Dunkel on Spiceworks for his work on backing up the AS400.
https://community.spiceworks.com/how_to/26183-how-to-automate-as400-iseries-backup-onto-windows-network
Also thanking IBM for the Hello World instructions.
https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/We13116a562db_467e_bcd4_882013aec57a/page/Coding%20in%20Free-Form%20RPG%20IV%20-%20Chapter%201%20Hello%20World

Run time error 5 Invalid Procedure Call or Argument

I recently ran into an issue when using the Shell function to call an external application from a VBA Script. This was a new issue for me as my application has been in use for many years throughout the world. I was ready to release an update and when testing the “Run time error 5 Invalid Procedure Call or Argument” message appeared.

Odd, or so I thought.

My first inclination was hit Google up and find out what was going on. Looks like I wasn’t the only one being affected by this.
What I found out was the issue was caused, in my case by the fact the path I was passing as a parameter to the Shell function had spaces in it. Duh, why wouldn’t it.

Nearly all of the solutions offered by many people were to simply enclose the path with double quotes.
While some reported success with the aforementioned fix, alas I did not find joy.

As I always like to do when confronted with something that seems hopeless ( I tried all kinds of variations of Shell and ShellExecute) I decided to sleep on it.
The next morning I once again hit Google up, still no joy.

Then it happened. Captain obvious flew into my office smacked me on the back of the head and viola, I had the answer.

You see, I grew up on computers when there was no GUI and filenames were restricted to a 8.3 naming convention and paths were limited to 256 characters and NO SPACES.

So there it was. I just needed to get the short path of the long path stored in the file system.

Here is a nugget of code for you that should alleviate your troubles. Of all the solutions I found I never did find this one. I post it here for posterity in the hopes it helps someone else.

Function ShowShortPath(filespec)
Dim fs, f, s
Set fs = CreateObject(“Scripting.FileSystemObject”)
Set f = fs.GetFile(filespec)
Return f.ShortPath
End Function

This worked for me where no other solution did.

Your welcome. 🙂

Scintilla Text Editor and the Context Menu

I use Scintilla in my AS400 Query Creator application and recently needed to modify the context menu when you right click the control. As usual I searched on Google and found Stephen Swenson’s blog and his version of a class extending the Scintilla one. His class gives you the ability to modify the context menu and it was just what I needed, except I needed it in VB.Net. Credit goes to Stephen, I just translated it for VB.Net

So here it is for any one else looking:

Inherits ScintillaNET.Scintilla
Private miUndo As MenuItem
Private miRedo As MenuItem
Private miCut As MenuItem
Private miCopy As MenuItem
Private miDelete As MenuItem
Private miSelectAll As MenuItem

Public Sub New()
MyBase.New()
initContextMenu()
End Sub
Private Sub mUndo()
Me.UndoRedo.Redo()
End Sub
Private Sub mRedo()
Me.UndoRedo.Redo()
End Sub
Private Sub mCut()
Me.Clipboard.Cut()
End Sub
Private Sub mCopy()
Me.Clipboard.Copy()
End Sub
Private Sub mPaste()
Me.Clipboard.Paste()
End Sub
Private Sub mReplace()
Me.NativeInterface.ReplaceSel("")
End Sub
Private Sub mSelectAll()
Me.Selection.SelectAll()
End Sub

Private Sub initContextMenu()
Dim cm = InlineAssignHelper(Me.ContextMenu, New ContextMenu())

Me.miUndo = New MenuItem("Undo", New EventHandler(AddressOf Me.mUndo))
cm.MenuItems.Add(Me.miUndo)

Me.miRedo = New MenuItem("Redo", New EventHandler(AddressOf Me.mRedo))
cm.MenuItems.Add(Me.miRedo)

cm.MenuItems.Add(New MenuItem("-"))

Me.miCut = New MenuItem("Cut", New EventHandler(AddressOf Me.mCut))
cm.MenuItems.Add(miCut)

Me.miCopy = New MenuItem("Copy", New EventHandler(AddressOf Me.mCopy))
cm.MenuItems.Add(miCopy)

cm.MenuItems.Add(New MenuItem("Paste", New EventHandler(AddressOf Me.mPaste)))

Me.miDelete = New MenuItem("Delete", New EventHandler(AddressOf Me.mReplace))
cm.MenuItems.Add(miDelete)

cm.MenuItems.Add(New MenuItem("-"))

Me.miSelectAll = New MenuItem("Select All", New EventHandler(AddressOf Me.mSelectAll))
cm.MenuItems.Add(miSelectAll)

End Sub

Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
If e.Button = MouseButtons.Right Then
miUndo.Enabled = Me.UndoRedo.CanUndo
miRedo.Enabled = Me.UndoRedo.CanRedo
miCut.Enabled = Me.Clipboard.CanCut
miCopy.Enabled = Me.Clipboard.CanCopy
miDelete.Enabled = Me.Selection.Length > 0
miSelectAll.Enabled = Me.TextLength > 0 AndAlso Me.TextLength <> Me.Selection.Length
Else
MyBase.OnMouseDown(e)
End If
End Sub
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class

MySQL – Insert a record only when it doesn’t exist

Inserting a record into a table when it doesn’t exist is pretty simple when your table has a unique key, but what if it doesn’t?

I had that problem recently. I need to run what amounts to a hourly transfer of records from one database, AS400 DB2 to a mySQL DB.

I could not reliably with the columns in the DB SELECT only the records that have not already been SELECTED. So the next logical step was to make sure the record did not exist in the destination DB.

For this the following SQL Statement works best if you do not have a unique key:

These are my column names: UTCSID, UTLCID, UTBIYY, UTBIMM, UTBIDD, UTTACN

First two are VARCHAR, with the rest being TINYINT.

INSERT INTO UT300AP (UTCSID, UTLCID, UTBIYY, UTBIMM, UTBIDD, UTTACN) Select * FROM (SELECT ‘12321’ , ‘32345’, 16, 4, 7, 2.0) AS tmp WHERE Not EXISTS(SELECT * FROM UT300AP WHERE UTCSID = ‘12321’ AND UTLCID = ‘32345’ AND UTBIYY = 16 AND UTBIMM = 4 AND UTBIDD =7 AND UTTACN = 2.0 ) LIMIT 1;

That is what I am using. You can SELECT based upon one, two or all of your columns. In my case I need to ensure that no record existed that was exactly the same as what I was looking to INSERT.

For those of you using vb.net to work with mySQL the following code does this for me:

Dim szInsertStatement = "INSERT INTO UT300AP (UTCSID, UTLCID, UTBIYY, UTBIMM, UTBIDD, UTTACN) Select * FROM (SELECT '{0}', '{1}', {2}, {3}, {4}, {5}) AS tmp WHERE Not EXISTS(SELECT * FROM UT300AP WHERE UTCSID = '{0}' AND UTLCID = '{1}' AND UTBIYY = {2} AND UTBIMM = {3} AND UTBIDD = {4} AND UTTACN = {5} ) LIMIT 1;"

szInsertValue = String.Format(szInsertStatement, szRow.Item("UTCSID").ToString.Trim, szRow.Item("UTLCID").ToString.Trim, szRow.Item("UTBIYY").ToString.Trim, szRow.Item("UTBIMM").ToString.Trim, szRow.Item("UTBIDD").ToString.Trim, szRow.Item("UTTACN").ToString.Trim)

Resetting User Passwords in Active Directory

So after 20 years of resetting users Windows passwords I decided I would code a small application that would be easier to use to handle this task. Yes I know there are a myriad of programs out there that will let users reset their own passwords. The problem is they cost money, usually on a per user basis. Why buy the cow when the milk is free? Thus ResetPWD was born. The application shows you a few different techniques that you may find interesting. The first is cryptography. I use this to safely store passwords on the hard drive. The other technique is for saving window positions when dealing with multiple screens. Lastly deals with Active Directory, resetting user passwords and making it so they have to change their password at the next log in. Most of the code is cobbled together from bits and pieces I found online. As always use it at your own risk, there are no warranties for fit or particular purpose and if you screw something up, it’s your fault, not mine.
When you first run the program, it will present you with a settings dialog box.
Capture-Settings

LDAP: This is the LDAP connection string you need to connect to AD and reset their password
Example: LDAP://EarthWindFire:389/DC=SomeDomain, DC=com
Domain: The fully qualified domain name of… your domain.
Username: The account you will use that has the privileges to change user passwords
Password: The password for the aforementioned account.
At the suggestion of someone online I actually just created an account for this purpose.
Once you have all that set, click the okay button and you are ready to change passwords.
The main window has two areas, the first is the text area where you will type in a username for which you want to change the password.
The second textbox is the password it will be set to. Now here I always reset a password to the same password. The users know it and its simple for them to remember. You can set it to whatever you want.

Capture-Main
Using this app is easy. Once its setup all you have to do is start the app up, enter the username you want to change passwords for and hit the enter key. If it’s successful, it will tell you and in 3 seconds close automatically.
I also made it so if you press the escape key the app closes. I did this so if accidentally open the app I can easily close it without having to mouse over to it.
Source code is zipped up here. You will need Visual Studio 2015 and .NET 4.6