Friday, December 30, 2016

The phpBB 2 to phpBB 3 converter messes up encodings

When I upgraded two forums to phpBB 3 from phpBB 2, some text apparently got messed up. The problem is classic; it took UTF-8 text, interpreted it as Latin-1, and then re-encoded it as UTF-8. This appears to be a problem with the converter - there are several threads on the phpBB forums about it, which I would link if their forums were currently available. I can correct that with a bit of SQL.

Unfortunately, the second forum converted got doubly butchered. I'm not sure exactly how, but it seems some sequences were unrecoverably damaged. That is, some are fine (well, at least recoverable by double-decoding), but some end with an invalid character. I'll need to manually search-and-replace the most common miscoded characters.

Thursday, December 29, 2016

Policy Plus - Show the last sources

Since it's possible that people might not remember what policy sources they were editing last time, and given that Policy Plus now remembers the last policy source (which is almost always the convenient thing to do), it's important for people to be able to see what they're currently editing. Therefore, I added a bit of code to the startup routine that sets up the "Open Policy Resources" dialog to be in a state that would produce the last policy loaders.

Wednesday, December 28, 2016

When the phpBB 3 upgrade fails with 500 Internal Server Error

Today I migrated two phpBB 2 forums to phpBB 3. The first went perfectly smoothly with no unexpected messages at all. The second had a couple apparently non-fatal warnings, but then in the middle of the database upgrade process it just halted with an HTTP 500 error. I could get no useful information out of the log. After hours of fiddling and refreshing and Googling, I found that some posts in the old database were tripping up the parser.

To figure out exactly which ones were problematic, I went into the new database and got the maximum post ID out of the posts table. I then queried for the posts in the old database with an ID starting a little bit before that number. Sure enough, one a little after the last successfully migrated post was insanely long with a bunch of weird markup. After replacing its content with a little note about why I had to remove it, the updater continued successfully!

Tuesday, December 27, 2016

Students can get AutoDesk products for free

AutoDesk makes software for architects, engineers, manufacturers, and animators. For example, they're the company behind 3ds Max, the powerful 3D modeling and animation program. I had heard of their products, but until recently I didn't know I could actually get them.

If you're a student with a .edu address, they let you have quite a bit of their software for free for three years for educational purposes. Visit their education section for more information and to install the software.

Monday, December 26, 2016

Policy Plus - Remember the last settings

If you open an alternate ADMX source, it's likely that you want to continue using it in future launches of Policy Plus. Before, Policy Plus just opened the default PolicyDefinitions folder and the normal local GPOs at startup. Today I added a little configuration manager to read and write settings from the Registry. At startup, Policy Plus loads the last ADMX source and policy sources. The ADMX source setting is updated whenever a full new source is opened; the policy source settings are updated when the policies are saved.

Sunday, December 25, 2016

Batch-like wildcards in PowerShell

Several commands and utilities used in batch scripting take filename filters that use * and ? as wildcards for multiple characters and exactly one character, respectively. In PowerShell, that kind of matching can be done with the -like operator, but it has a couple extra features (e.g. # for a numeric character) that make it not match batch behavior exactly. Therefore, to use it on arbitrary filters and get it to work like classic batch, you should first escape some characters in the filter:

$input -like ($filter.Replace('[', '[[]').Replace('#', '[#]'))

Based on my Super User answer.

Saturday, December 24, 2016

AbiathRPC - Little bugs

While combing through AbiathRPC, I found a couple small bugs which are now fixed.

First, authentication wasn't actually being checked in the WCF method that updates a batch of tiles. Fixed by adding the appropriate login-checking call.

The Abiathar client with the AbiathRPC state wrapper would crash when updating tiles when not connected to a server. This was caused by the replacement state wrapper trying to submit updates from a list that didn't exist to a server that didn't exist. Fixed by checking that there's actually an RPC connection and stopping with the vanilla behavior if there's not.

(Also, merry Christmas from Abiathar - from now until sometime tomorrow night, the Abiathar splash screen is Christmas-themed.)

Friday, December 23, 2016

The surprising OWNER RIGHTS principal

Windows has a security principal called OWNER RIGHTS. Like several other all-caps principals, it doesn't apply to anyone in particular. It defines the access that the owner of the object is given even if not otherwise allowed. The surprising part is that the mere presence of an access control entry for this principal blows away the default rights granted to the owner (the ability to read and write the access control list). If you add an entry for this principal with no permissions, being the owner is no longer special other than in that the file size counts against the owner's disk quota.

Thursday, December 22, 2016

What does the Distributed Link Tracking Client service do?

Windows is surprisingly good at keeping track of files that have shortcuts pointing to them. If you move a shortcut target to somewhere on the same volume, using the shortcut will find the target file by its NTFS object ID. You wouldn't even know anything had happened in the background.

If you move a file across volumes, though, it's object identifier changes. (Check this with the fsutil utility.) Yet somehow Windows still manages to find the file if it's pointed to by a shortcut! This is the work of the Distributed Link Tracking Client. You can test this by stopping the DLTC, moving a target across drives, and trying to use the shortcut - it'll be broken.

On a standalone machine, the DLTC keeps an eye on file movements to repair shortcuts. On a domain, it reports to the domain controller, which stores the movement information in the Active Directory to help all client computers find files on the network.

Based on my Super User answer.

Wednesday, December 21, 2016

Windows does not keep track of last-access time by default

One might wonder why the last-access time never seems to update when files are opened. After all, a file has to be accessed to open its contents.

The reason is that Windows, as of Vista, no longer updates the last-access time by default because that would involve a write every time a file is opened, even if it was just supposed to be a read. If you really want that updating back, you can run this command:

fsutil behavior set DisableLastAccess 0

Based on my Super User answer.

Tuesday, December 20, 2016

When does text direction get affected by a previous RTL character?

Suppose you have this text in a text field:

abc123'ß¡'

That triangle character is U+07E1 NKO LETTER MA. It's marked as a right-to-left character, since it comes from the N'Ko alphabet, which is written from right to left.

Now for some experiments. Try typing a number after the triangle but before the closing quote. It will appear to be inserted before the triangle! Hit Backspace, then move to the very end of the string. Type a normal dash. It's not teleported. That character's bidi class is "European separator", which is listed as weak. But now type a number after that, and the string gets shuffled into this:

abc123'ß¡'-4

The order of the last quote, hyphen, and number appears to be flipped. Interestingly, digits have the "European number" bidi class, which is also weak. So why did the number cause the flip?

Unicode RTL rendering rules mandate that number characters (that don't already have their direction forced upon them) take on the direction of the last character behind them that had a strong preference. Neither the quote nor the hyphen did, so the new number becomes RTL, and it takes the in-between characters along for the ride.

Based on my Super User answer.

Monday, December 19, 2016

Holding an executable inside a batch file

Suppose you want to include an EXE inside a batch file and have the batch script extract the program from itself and run it. Just pasting the EXE into the file will almost certainly butcher it, because programs are binary files and batch scripts are text files. Therefore, you'll need to encode the binary data.

Start with this batch file:

@echo off
powershell -command "[IO.File]::WriteAllBytes('extracted.exe', [Convert]::FromBase64String((gc '%0')[-1]))"
extracted
del extracted.exe
exit

REM Base64-encoded program will be inserted below


The extra blank line at the end is important.

Notice that the PowerShell script embedded in the second line takes a Base64 string from the end of the batch file. To put it there, use this PowerShell command:

[Convert]::ToBase64String([IO.File]::ReadAllBytes('C:\fullPathTo\file.exe')) | Out-File 'batchFile.bat' -Append -Encoding ASCII

Running the batch file will decode the executable, save it to disk, run it, and delete it once it finishes.

Based on my Super User answer.

Sunday, December 18, 2016

AbiathRPC - Anonymous is not a person

Today I realized that the usefulness of the VeriMapsApproved setting (which allows any VeriMaps-authenticated user to connect) for the AbiathRPC server is undermined by the public availability of the Anonymous key. Server operators might enable that option think it will allow in known members of the community - since only I can issue new certificates - but it actually allows anyone who bothers to download the Anonymous key. Therefore, I made that account an exception to the approval granted by that server option.

If server operators want to allow the Anonymous certificate to be used for authentication, they can still add it as a normal account without a password.

Saturday, December 17, 2016

AbiathRPC - Save levels locally

If you're working on a leveling project with some people, it's great to have a centralized copy of the levels (on the AbiathRPC server), but you also need to be able to get the newest version so you can test your changes in a game. Today, I added an option to the RPC menu that saves the current state of the levels to local files. Its implementation is very straightforward; the only special thing it does is check for the presence of a GAMEMAPS file in the current folder and fill the suggested file names with that file's extension.

Friday, December 16, 2016

AbiathRPC - Administration GUI

Yesterday I wrote the AbiathRPC server functions for user management. Today I put together the client UI that actually uses those.


In the above screenshot, Anonymous can only authenticate with VeriMaps; it has no password set. It is also a server administrator. The Test account can authenticate with a password, but it is not an admin.

The buttons are fairly intuitive: New Account adds a user, Set Password adds or sets a password for a selected user, Disable Password removes a user's password (allowing VeriMaps only), Promote/Demote toggles administrative privileges, and Delete Account removes the account from the server's configuration.

Changes to user configuration are saved to disk when the server shuts down.

Thursday, December 15, 2016

AbiathRPC - Administration APIs

There should definitely be a way for AbiathRPC server operators to manage their servers without having to actually remote in to the host machine, stop the server program, fiddle a textual config file, and restart the program. I think it makes sense for some management tools to be included in the Abiathar extension itself. So today I added a few WCF endpoints on the server: to get the allowed users, to delete a user, to create a user, to reset a user's password, and to set a user's access level. Those are all implemented, but I haven't yet put together a GUI on the client to use them.

I also adjusted the part of the server that decides a newly connected user's authentication plan. Now, even on an open-access server, users with a definite password will actually be required to enter their password if they use their registered username. Users without accounts are still free to pick whatever name they want and use it with no special access or authentication.

Wednesday, December 14, 2016

You can play "Myst 3: Exile" with ResidualVM

It's very difficult to get Myst III: Exile running on modern Windows if you only use the original media. Though ScummVM can run the original Myst and its sequel Riven, it doesn't work on Myst 3. For that, you'll need its sister project, ResidualVM.

The folder structures you'll need to copy from installation media vary depending on which ResidualVM build you use. If you use the latest stable release, follow the instructions on the web site. If you use the newest development build, use the ones in the GitHub repository.

Tuesday, December 13, 2016

AbiathRPC - Clean up old WCF instances

I just noticed that the AbiathRPC server never properly disposed of communication objects for clients that had abruptly disconnected; they just hung around in the list of server object instances. Since they're in that list, the server always tried to notify them of new events. Today I added some code to the routine that runs every ten minutes to save the levels if necessary. It now goes through all the current connections and removes the ones that are no longer working.

I also found that non-authenticated clients received event notifications because they were in the list, so I made the "notify all the other clients" routine only send the data to authenticated users.

Monday, December 12, 2016

Volunteering at a rescheduled FTC meet

The last FTC robotics meet in the area was cut short due to difficulties with the electronics in the beacons. Its second slate of matches was hastily rescheduled to today. For an unexpected meet, it was arranged very nicely, with a practice field and a competition field that worked well. Though I was assigned to do field inspections again, I could not arrive in time for those because I had to take some exams. I did manage to handle field reset for all but two of the matches. There was only one beacon-related problem, and the referees had a spare one on hand with which to swap it out.

Sunday, December 11, 2016

Testing whether a given user is an administrator with PowerShell

Given a user object $u, you can use this PowerShell line to check whether that user is an administrator, i.e. a member of the Administrators group:

(Get-LocalGroupMember 'Administrators' | ? {$_.SID -eq $u.SID}).Count -ne 0

User objects come from the Get-LocalUser or Get-LocalGroupMember cmdlets. The former lets you get a user by name, which is more useful here.

Based on my Super User answer.

Saturday, December 10, 2016

How Windows Firewall knows whether it has prompted the user to allow a program

When a program tries to start listening in a manner that doesn't match an existing firewall rule, Windows Firewall pops up a dialog asking whether to allow the program through the firewall. No matter whether you choose "Cancel" or the choice that lets it through, a new rule is created, to block or allow traffic from that EXE, respectively. The interesting part is that rules created in this way are marked specially in the Registry. All the rules are kept here:

HKLM\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\FirewallRules

Each program-related prompt creates two rules, one for TCP and one for UDP. The Registry value names start with TCP Query User and UDP Query User, respectively. To bring the prompt back, remove those rules either by deleting them in the Windows Firewall MMC snap-in, or by deleting the corresponding Registry values then restarting the Windows Firewall service.

Based on my Super User answer.

Friday, December 9, 2016

AbiathRPC - Password hashing

AbiathRPC server operators can allow users to authenticate by password or VeriMaps certificate. The VeriMaps certificates themselves are never seen by the server, but servers did store the plaintext passwords. Today I made the password authentication system using hashing, so people's passwords aren't on disk. This has the added advantage of stopping bizarre characters in new passwords from breaking the configuration file.

Server operators can still easily give people initial passwords; there's a PasswordIsHashed field that determines whether the user record's password field should be considered a hash instead of a plaintext. A plaintext will be automatically hashed at startup.

Thursday, December 8, 2016

AbiathRPC - Reconnection crash fixed

Yesterday I mentioned an AbiathRPC bug that caused the opening of a remote level set to fail after closing one that was opened successfully. I found that the crash occurred when setting up the watchdog render planes; an original GalaxyLevel was incorrectly cast to a TaggedGalaxyLevel in the method that looks up a level ID for a given level wrapper.

The problem was that the bookkeeping on level substitutions wasn't nullified at disconnection. That made the ID lookup function think the connection was complete when it's wasn't. The old level objects were also kept around, which is less than ideal. I added a single line to the connection-closing method to fix the problem.

Wednesday, December 7, 2016

AbiathRPC - Change password

Today I added a way for AbiathRPC client users to change their passwords on the server. There is a new "RPC" menu that is only visible when connected to an AbiathRPC server; currently, its only item is Change Password. The resulting form has the user enter the current and desired new password. The server verifies the existing password and updates the user record with the new password. The password changes along with other configuration changes are committed to disk when the server exits.

I noticed that the AbiathRPC client crashes when reopening a remote level set after having closed one, so something isn't quite right with the disconnection routine.

Tuesday, December 6, 2016

Reading Word document properties in PowerShell

Word documents include some extra properties like "total time spent editing." These properties aren't visible in Explorer because they're just data in the file. You could use COM to interop with Word and read them, but it's not super hard to grab the data directly from the file.

Modern Word documents are just ZIP files, mostly containing XML files, both of which PowerShell can handle. This little script outputs the total editing time of a given Word document:

$zip = [System.IO.Compression.ZipFile]::Open($filename, 'Read')
$propsentry = $zip.GetEntry('docProps/app.xml')
If ($propsentry -ne $null) {
    $stream = $propsentry.Open()
    $reader = New-Object System.IO.StreamReader $stream
    $content = $reader.ReadToEnd()
    $xmldoc = [xml]$content
    $xmldoc.Properties.TotalTime
}
$zip.Dispose()

The time is measured in minutes.

Based on my Super User answer.

Monday, December 5, 2016

Volunteering at another FTC meet

This Saturday, I volunteered at another qualifying FIRST Tech Challenge robotics meet. Like before, I was a Field Inspector, but I also got to do Field Reset this time.

I started out with field inspections. There were 11 teams, most of which got through without any issues. Since this wasn't a league championship, outdated software was acceptable, so I just warned teams that needed to update that it wouldn't fly at the big meet. I was apparently the only Field Inspector, so when multiple teams came over at once, the Control System Adviser helped inspect some. There were a couple instances of robots not driving due to hardware profile mismatches, but those got sorted out and they were all ready by the time matches started.

Field Reset is much easier with this year's game than last year's. Here, I just had to move some large exercise balls back into the middle and put the small wiffle balls back on the sides. (As opposed to last year, where I had to pick up dozens of cubes and wiffle balls and then hurl them onto the field at the start of the next match.)

Unfortunately, the electronic beacons started failing after being buffeted by the robots throughout the matches. We tried to simulate them with volunteers holding alliance flags to indicate beacon color, but that was always a judgment call as to whether the robot actually hit the button. After the first of two sets of 17 matches, the teams' coaches convened and decided to reschedule the second set. That was for the best, since we were already more than an hour behind from the beacon trouble. Hopefully a venue and date can be found for this meet's thrilling conclusion.

Sunday, December 4, 2016

Using Chrome's --disable-extensions-except

As of version 55, Chrome supports the --disable-extensions-except flag, which as you might expect, disables all extensions except the one specified. The trick is that it has to be specified as a path to a folder containing an unpacked extension. For an extension you're building, that's easy, but for ones you got from the store, you have to hunt down the folder where they're kept. Chrome unpacks installed extensions here:

%LOCALAPPDATA%\Google\Chrome\User Data\Default\Extensions

Inside are a bunch of folders each named with an extension's ID. Inside those are folders for versions of the extensions, and those are the folders that have manifest.json. Pass that folder to Chrome like so:

chrome --disable-extensions-except="C:\path\to\versionfolder"

Based on my Super User answer.

AbiathRPC - Make sure the connection gets closed

When a remote level set is closed, it's important that AbiathRPC clean up and realize that it's no longer supposed to be talking to that server. I already had an event handler on the Close menu item, but a level set can also be closed in the process of a new one opening, which bypasses that event handler. Fortunately, the level label is updated during the close process, so I added a check for the current level set being gone to the existing handler. If the main level set is missing, it initiates AbiathRPC disconnection, which cleans everything up.

Friday, December 2, 2016

Version number strings aren't automatically sorted as versions should be

Let's say you have some strings describing version numbers, like 1.1, 1.2, all the way up to 1.11. If you try to do a newer-version check using only string comparison, it will appear that 1.11 is older than 1.2. Most sorts sort those texts that way because "1" indeed sorts before "2", so it stops checking. (It doesn't think about numeric value at all.)

Instead, you should do some number comparisons. For example, using the SMBIOSBIOSVersion WMI property (a string) will be more difficult than using the SMBIOSMajorVersion and SMBIOSMinorVersion properties, which are integers.

Based on my Super User answer.

Thursday, December 1, 2016

Unbanned from Dropbox public linking

A while back, my Dropbox account's public links stopped working and stayed that way for a good long while. Eventually, I got in touch with someone via e-mail and explained the situation as I had done in the original ticket. The ban was indeed automatic; as I surmised, one of the executables I was hosting (unlzexe.exe) was considered malware by their system. Again, it's not malicious, but it does modify other EXEs, so it could be used for bad purposes. Abiathar uses it to decompress the Keen games' executables.

On September 6, Dropbox manually lifted the block. I am no longer hosting unlzexe.exe there, but Dropbox has continued to work well for my other resources.

Wednesday, November 30, 2016

AbiathRPC - Version check

I might eventually want to add some features to AbiathRPC after its first public release. Therefore, it'll need some sort of versioning system. I added an operation contract to the server's service contract that gets a string describing the server's version. If a client connects to a server with a different version, it warns the user about possible bizarre behavior. Since the client reports its own version when asking for the server's, the server has the opportunity to lie about its version if it decides it can accommodate the client despite their differences. That ability may or may not prove useful as I add more features after a release.

Tuesday, November 29, 2016

AbiathRPC - Remote ADEPS fragment

AbiathRPC level sets can't have all the fancy configuration available to local level sets because there isn't a real ADEPS file to load. For example, there isn't a way to set the number of infoplane tiles, which is kind of a problem because it's different for different episodes. So I added a server configuration option that has it load an ADEPS fragment from a file. When a client connects, it asks for that fragment and if it's found, the connection routine has the core configuration object load that text. Servers can now share these extra properties - e.g. path tile IDs, Level Inspector and Resource Accountant configuration - with clients.

Monday, November 28, 2016

AbiathRPC - Keep unnecessary menus disabled

Though I had already added code to AbiathRPC's connection routine to disable the menu items that don't make sense for a remote level set, I found today that they get re-enabled when the user switches levels. That's because Abiathar's SetCurLevel looks through the list of lockable menus and sets each to an appropriate state depending on whether there is a level set and whether there are any levels in it. I added an event handler on the TextChanged event of the level name label (which is fired after the level name indicator is updated, which is after menu re-enabling part) to disable those menus again.

Sunday, November 27, 2016

AbiathRPC - Debugging level creation

I noticed today that though creating levels in AbiathRPC worked, trying to edit the new ones in the instance that created them would cause a crash. The old level wrapper (one around the plain GalaxyLevel) was still held in the current tool. Even after I made ScanForLevelSetChanges refresh the current tool when necessary, the watchdog render planes were still holding onto the wrong wrapper. There isn't a convenient way to make sure they always have the right kind, so AbiathRPC now keeps a table of plain level instances and tagged ones, updating it when a new level is created and consulting it when looking for a given level wrapper's level ID. Editing new levels now works.

Saturday, November 26, 2016

Opening a file from Task Scheduler

Some might think that to open a file (e.g. a plain text document) from Task Scheduler, you need some sort of script to use Windows's "open this document with whatever it needs" mode. Interestingly enough, you don't - and since you don't have to, you don't have to see the flash of a command prompt or whatever you use to launch the final thing. Instead, you can just put the full path to the target document as the "program" in a "start a program" action and sure enough, when the task is run, up will pop that document in its default application. (Caveat: Task Scheduler doesn't seem to like spaces in the path, even if you quote it.)

Friday, November 25, 2016

A guide to installing Abiathar on Ubuntu 14.04

Last time I tried Ubuntu, I never got anything interesting running on it. Today I tried again, and after a ton of fiddling I managed to get Abiathar running on it. Note that I barely know anything about Linux and I'm just compiling a bunch of instructions into one place.

First, you'll need to download the update client (EXE link), which fetches the newest version. Your Downloads folder is a good place for that. Fire up a Terminal and navigate to wherever you put it. Mark it executable with chmod +x AbiatharUpdater.exe.

Now you need Mono, which is like .NET for Linux. Open the Ubuntu Software Center application, then find and install the Mono Runtime (searching for "mono" should pull it up). You need some extra packages:

sudo apt-get install mono-vbnc
sudo apt-get install mono-devel

Unfortunately, those don't include the SSL certificates that Mono needs to fetch HTTPS files, and mozroots is no more, so we need to add another repository?
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
sudo apt-get update
sudo apt-get install ca-certificates-mono

For reasons unknown, installing that last certificates package takes a really long time and pokes at a bunch of other packages. Once it's done, you can finally run the Abiathar updater.

mono AbiatharUpdater.exe

If everything goes well, it will download three files. It fails with "The method or operation is not supported" at the very end, but that's OK; it was trying to launch Abiathar using a Windows function that doesn't exist on Linux.

OK, now we need WINE, which is a Windows emulator. (Abiathar needs a UI, which means window handles and stuff that isn't .NET, so just Mono won't do it.) Before we do that, mark Abiathar executable with chmod +x Abiathar.exe.

sudo apt-get install wine
sudo apt-add-repository ppa:wine/wine-builds
sudo apt-get update
sudo apt-get install winehq-staging

That installs the normal WINE package, then it gets the staging (development) branch, which has features we need. Now we need to configure stuff to get the .NET framework running inside WINE.

rm -rf ~/.wine
export WINEARCH=win32
export WINEPREFIX="/home/USER/.wine"
winecfg

Replace "USER" with your home folder's name. The last command produces a GUI configuration utility. While it's loading, it might ask to install some things; install them. Once the dialog comes up, change the Windows version dropdown to Windows 7, then OK out. Now we need extra WINE-related utilities to get .NET.
mkdir Winetricks
cd Winetricks
wget -r -c -N https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks

That downloads a script from the Winetricks GitHub repository. cd down through all the new folders.

chmod +x winetricks
sh winetricks

When you get a GUI, choose to "Select the default wineprefix", then choose "Install a Windows DLL or component." Scroll through the list and find dotnet40. It'll warn you about lacking support, but that's OK. Soon, you'll get the normal .NET 4 installer. Go through it as usual, and once done, cancel out of Winetricks.

Finally, cd back to where you put Abiathar, and run it.

wine Abiathar.exe

Abiathar running on Ubuntu

Thursday, November 24, 2016

AbiathRPC - Level creation message size

While testing AbiathRPC's new ability to replicate newly created levels, I found that the client "received no meaningful response" from the method call that sent the level's contents to the server. I recalled that this had also happened when downloading the initial levels from the server, I remembered that I need to adjust the MaxReceivedMessageSize on the server end as well to allow it to handle the big packages that include full levels. With that done, the crash went away.

Wednesday, November 23, 2016

AbiathRPC - Scan for level set changes

Today I wrote all the parts of AbiathRPC that are involved in level creation and deletion. When the level set is marked as changed, AbiathRPC compares the current level set against its internal bookkeeping to see if any levels were deleted or added. If anything is found, it notifies the server. When a notification comes in as a result of another client doing something, AbiathRPC pokes at the main form to insert or delete the level as appropriate, then updates its bookkeeping.

Noticing deletion was more difficult than expected because with explicit interface implementation and inheritance, callers that know a real class that implements the interface will always call the original method. Therefore, I had to add an event handler to the level deletion menu itself to run the scan for changes.

I also disabled the Reload Graphics menu item for remote level sets because it would just break things.

Tuesday, November 22, 2016

Finding the physical sector size of a drive with no volumes

There are plenty of ways to get the logical sector size of any attached drive on Windows (e.g. wmic, msinfo32), but it's not very obvious how to get the physical sector size without there being a volume on the drive. Recently, I stumbled upon a PowerShell cmdlet that produces that information: Get-Disk. The output has both LogicalSectorSize and PhysicalSectorSize properties. Unfortunately, this cmdlet appeared in Windows 8, so I don't know a way to get this data on Windows 7 or earlier.

Based on my Super User answer.

Monday, November 21, 2016

AbiathRPC - Close, don't save

It's important that AbiathRPC be involved in the process of closing a level set because it needs to update its own bookkeeping to note that it's no longer connected to a server. (And, of course, it should also actually close the connection.) So today I added a part in the "add menu items" event bus stop that attaches an event handler to the Close menu item's Click event. When that runs, AbiathRPC disconnects.

I also noticed that it would be bad if the Save button worked as normal, creating a local copy that wouldn't work because of the lack of real graphics sources. Saving manually is also pointless, since changes are replicated to the server and other clients immediately. Therefore, during the initial connection, AbiathRPC now disables the Save menu item. I made sure it gets re-enabled if the user closes the connected level set and opens a local one.

Sunday, November 20, 2016

AbiathRPC - Live updating

Today I implemented the "tiles changed" notification receiver in the AbiathRPC client. It runs mostly in an Invoke call on the main form to prevent threading headaches. While processing the tile updates, it sets a variable that signals the watchdog notification receivers that render plane updates shouldn't be treated as real local changes. Then it just updates the level data appropriately, marks the tiles dirty on the render planes, and causes a screen repaint.

I tested this with two clients connected to the same server, and changes from one client are indeed replicated in real time to the others. Now I need to detect and replicate full-plane and level metadata updates.

Saturday, November 19, 2016

Markeen - Try removing the originality constant

Markeen's generation order has changed quite a bit since the original weighted random function was edited to include an originality constant (which biases the results toward or away from commonly-used tiles). That constant for a long time was set at 1.2, slightly favoring more common tiles. Recently I wondered whether that was actually useful now that Markeen has a smart fill order. I tried removing that adjustment - by setting it to 1 - and the levels certainly did change. The change made it much more common for multiple different platform styles to occur in the same level and therefore collide, but it did make other things fit together better (e.g. poles). I wonder if I could get the advantages of this without the platform collisions.

(I would upload pictures, but currently my Internet is super unreliable; it's losing at least half the packets sent.)

Friday, November 18, 2016

You can get Myst Masterpiece Edition from the Internet Archive

The Internet Archive has Myst Masterpiece Edition available for download. To actually use it, you'll want the BIN and CUE files from this directory. To convert that BIN into an ISO for free, you can use the demo edition of WinISO. Finally, if you have Windows 8 or higher, you can mount that ISO as a virtual CD drive; otherwise, you can extract it with 7zip or WinRAR.

To play it on a modern computer, you'll want ScummVM. Copy the necessary Myst files from that ISO into a new folder, then run ScummVM. Select the folder where you put those files, and you're good to go.

Thursday, November 17, 2016

AbiathRPC - Writing to the server

Today I wired up all the previously-stubbed parts of the AbiathRPC client that get notified of local changes. They now keep records of pending updates, and when MarkChangesMade is called, those changes get pushed to the server.

I decided to abolish the server-side checks for out-of-order tile updates, since they just made things more complicated, especially if I wanted to make them work on full-plane updates. "Last writer wins" makes a lot of sense anyway. Speaking of full-plane updates, full-level updates are temporarily removed because they're basically the same as either three full-plane updates or a level deletion/creation cycle. (The latter will be used in metadata changes.)

After fixing a bug that left the original stub level in the memory of the first tool, AbiathRPC can successfully write to a server from one client! Changes are indeed persisted on the server. The next thing to do is write the parts of the client that receive server updates so some real-time collaboration can happen.

Wednesday, November 16, 2016

AbiathRPC - Watchdog planes

A very important part of AbiathRPC is the ability to detect changes. Today I started working on making that possible. I could have patched the view state class at runtime like I did the state manager, but I'd prefer to avoid reflection if possible. Render planes are always notified of changes, so a bunch of invisible dummy planes ought to do the trick. I added a stop for the event appropriate bus that injects those few render planes (one for each real plane, plus one that's only hit when the entire level is marked dirty).

The new watchdog plane class notifies the controller extension when a tile change is made or when the whole plane is invalidated. I've added an event listener for the main view's painting; that will be when the batched updates are delivered to the server. Waiting until a visual refresh can be done guarantees that the last tool finished whatever it was in the middle of doing when the planes were notified of the changes.

Tuesday, November 15, 2016

You can customize the Recycle Bin more if you redirect folders

The Recycle Bin allows you to tweak its settings (maximum size, whether to permanently delete) for a few specific folders, but only if those folders are subject to redirection to a network share. Usually that redirection is set in an Active Directory environment, but you can whack the Registry to make it work on a standalone computer too. The relevant values are here:

HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders

Only the folders shown there are eligible for redirection. Actually, the set of folders the Recycle Bin tweaking will work on is the intersection of that list and the list of known folders. Once you've redirected the folder, you can move to the BitBucket Registry key under Explorer
and add a new subkey KnownFolder. Inside there, create another subkey with the curly-braced {GUID} of the target folder. The DWORD values NukeOnDelete (0 or 1) and MaxCapacity (in megabytes) control the behavior of the Recycle Bin for files deleted from that folder.

Based on my Super User answer.

Monday, November 14, 2016

Allowing users to create things in a folder but not modify other things

Sometimes people want to allow users to create new items inside a given folder but not mess with the other things people have put there already. This can be done with Windows access control lists.

The trick is to give all users write privileges on the directory itself, but not apply that entry to subfolders and files. (Read permission to everyone can be granted on contents if desired.) Then, a full-power Allow entry for CREATOR OWNER can be added that applies to subfolders and files only, not the top folder. When a new object is created in the folder, its creator gains all privileges on that object only.

Based on my Super User answer.

Sunday, November 13, 2016

Markeen - Tharify test

For the sake of seeing how it would go, today I ran Markeen on some Keen 3 levels after putting them through Tharify, the Vorticons ←→ Galaxy level converter. They all turned out basically the same: a mostly empty level with solid ground at the bottom and a few blocks and point items scattered through the sky.






(Imgur album of all the above.) These were generated at a profile depth of 2. Though multiple passes were allowed, only one was taken because of the tiny amount of failure tiles.

I believe these turned out this way because of the dramatic simplicity of the Keen 3 tileset compared to the Keen Galaxy ones - there's usually no difference between the different faces of a platform here, so Markeen doesn't have much information to go on on how it should form structures.

Saturday, November 12, 2016

Markeen - Keeping options open

I noticed that Markeen still has issues with structures colliding with each other. Therefore, I thought it would be helpful to make the tile chooser avoid creating impossibilities. So I wrote up a change to the branch where there are multiple options and knocked out choices that would increase the number of unfillable spots. Unfortunately, making this work at higher orders seems very challenging, so it currently only works at one level. And, of course, failure is sometimes unavoidable at this depth. This feature has successfully altered some choices for improved quality, but it affects way less than one percent of the tiles in each level.

I also saw that some tiles should have been manageable, but were blocked for poor reasons (like a point item being too near what could easily be a pole cap). So at the end of the last pass, I now have Markeen iterating over all the failed tiles and placing the singular one that fits one of the sides - something of a resurrection of the now removed rare structure generator.








If you look closely, you'll find some placed tiles that don't quite fit together. Those are the products of the fallback placer; they would otherwise be normal failures. These levels were generated with a target of 9 maximum failures, 3 passes, and a profile depth of 2.

Friday, November 11, 2016

Markeen - Regeneration passes fixed

Last time, I was very pleased with the quality improvements from the smart fill order. After looking harder at the images with the regeneration passes done, though, I realized that they didn't seem any better or worse than the ones with no extra passes. Looking at the code, sure enough, when I disabled the rare structure generator, I accidentally caused every spot to be flagged as failed.

Once I fixed that, the process ran much faster, and produced some pretty nice levels.







These were generated by a 2-deep profile with a maximum of 4 passes.

Wednesday, November 9, 2016

Markeen - Good at low profiling depths

I wondered today how much Markeen's new slowness is increased by each level of profiling depth. So, for curiosity, I tried it at a depth of 2 as opposed to 5. It went a lot faster, completing each level in a handful of seconds.

And, to my shock, they also looked good!






Those are very, very good compared even to yesterday's. And only at one pass! I set the number of passes to three and tried again.






Still not perfect, but pretty good. I have a couple new ideas for performance and quality, so I think things can get even better.

Tuesday, November 8, 2016

Markeen - Smart fill

I just wrote a smarter method of determining the fill order for Markeen. Previously, I already had a method to calculate the probabilities of each tile in a given space. I used that to determine a "diversity of options" for each not-yet-filled tile. Instead of using a predetermined order, the filler now deals with the spaces with less diversity first, since the more diverse ones can presumably accommodate more choices.

I did my best to include some caching, but handling of all those probabilities for every place is expensive. Markeen is at least a hundred times slower now, even after I temporarily disabled the rare structure handling (which is difficult to integrate with the cache updating). The levels seem alright, but this new strategy isn't a magic bullet. I do think there's still more to explore with it; I haven't tried to fine-tune the diversity computer at all.

Here are all ten levels I generated with this new version:











(Click to enlarge.)

Monday, November 7, 2016

AbiathRPC - Logging

I haven't had much time today to develop any of my fun projects, but I did slightly adjust AbiathRPC. It now logs the basic user actions: connection, disconnection, authentication attempts. Instead of using Console.WriteLine everywhere, there's now an actual logging method that includes the timestamp in the output. In the future, I'll probably have this also write to a log file.


(This "Anonymous" is the one with the publicly available VeriMaps certificate. AbiathRPC users need to provide a username to connect.)

Sunday, November 6, 2016

AbiathRPC - Infrastructure for editing

Today I wrote the parts of AbiathRPC Server that allow clients to actually edit the levels. That consists of a few WCF method contracts: one to add a level, one to remove a level, and one to edit tiles in a level. That last one is a little interesting, because it's possible that a client could have edited a tile in between when a different one issued a write and when the server received it. Currently, I have the server not change the tile again when it sees that's happened, but I'm not sure whether that's a useful check.

Anyway, calling any of those methods results in the server taking note that changes were made. It saves the levels to disk at ten-minute intervals if there are any unsaved modifications.

Since clients will need to occasionally encode levels into LevelInformation instances (when creating a level with existing data, e.g. by resizing or loading an ASLEV), I refactored the level translation code out of the server and into the bindings library so it can be used by both server and client.

It looks like the server doesn't need to be as complex as I thought. Getting the client to hook all the right places in Abiathar will be the next thing to do.

When an FTC robot controller won't move the motors

Today I was helping an FTC team with its programming. The programming went perfectly fine, but getting the robot to act on it was more difficult than expected. The joysticks were connected to the driver station and through that to the robot controller, but no motors moved. I was super baffled, because I was told that a very similar program had worked before, and I saw the states of the joystick controls on the robot controller's screen.

After much Googling, I found something that suggested rebooting everything and connecting the robot controller's USB cable last. That worked! Both the original program and the new one were able to operate the motors.

Friday, November 4, 2016

StartCom is probably going away

StartCom is a root certification authority (CA) that has historically provided free SSL certificates. I've used them for a couple of my domains, and I've been very happy with the experience.

A while ago, though, it was discovered that StartCom's new owner WoSign had engaged in some sketchy behavior (intentionally backdating certificates). They also had severe bugs that allowed people to get valid certificates for domain's they don't own, which is a Very Bad ThingTM. Google Chrome has started phasing out its trust of those two CA's. I believe Firefox is also doing something similar.

This is basically a death sentence for that company, as it was for DigiNotar.

Wednesday, November 2, 2016

Policy Plus - Take ownership when downloading ADMX files

Today I tested Policy Plus's Acquire ADMX Files feature on a new computer. It successfully downloaded and unpacked the MSI, but when it tried to move the ADMX files, it died. I had forgotten that the PolicyDefinitions folder is by default owned by TrustedInstaller, which is the only principal that can write to it. I hadn't noticed this before because on my main computer I temporarily moved PolicyDefinitions for testing so I wouldn't overwrite it.

The solution is, of course, to adjust the ACLs on the destination folder before trying to move things there. The trick in this case is that administrators don't have write-DAC privileges on it, so SeTakeOwnershipPrivilege has to be enabled first, allowing the program to set the owner to the Administrators group. I refactored the privilege-enabling parts out of PolicyLoader into a new Privileges class for ease of enabling any privilege. (In this case, I also enabled SeRestorePrivilege so the DACL could be updated at the same time as the owner.)

I also found a bug that caused the move to fail if an overwrite was needed. That was easily fixed by first deleting files that need to be replaced. Everything works now.

The changes are live on GitHub.

Tuesday, November 1, 2016

Opening the Keen 4 demo version in Abiathar

A while back, someone asked me how to open the Keen 4 demo version in Abiathar. That's tricky because it doesn't come with an external EGAHEAD, EGADICT, or MAPHEAD. I had an interesting time getting those because the executable is compressed with PKLite instead of LZEXE, so UNLZEXE didn't work. Eventually I did get it decompressed with UNP.

After a few minutes of fiddling around in a hex editor, I extracted the three necessary files. You can download them here. Interestingly, I saw that the EGA header has 4-byte entries unlike the 3-byte entries in the full game. Even after I got that file, though, I didn't know where this version starts its tiles. To find that out, I used KeenGraph, which has the really awesome ability of auto-detecting chunk layout.

All in all, this is the Abiathar New Project Wizard configuration for the Keen 4 demo version:

  • Template: Keen 4 with advanced settings
  • Level Format: Carmack
  • EGA Layout: 4, 478, 1296, 1774, 2916
  • Tile Partitioning: defaults
  • Containing Folder: pick your folder
  • Level Source: start from existing files
  • Level Files: original GAMEMAPS and my MAPHEAD
  • Graphics Source: EGA resources
  • Graphics Files: the original EGAGRAPH and my EGAHEAD and EGADICT
  • Tileinfo Source: never use tileinfo
I confirm that those settings work. To me, the demo levels look extremely similar to the final ones, except that most of the ones present in the full game are missing here.

Monday, October 31, 2016

"Uninstalled processes" in the "App history" tab of Task Manager

If you go to the App history tab of Task Manager on Windows 8 or newer and then enable Options | Show history for all processes, you'll probably get an extra entry called "Uninstalled processes" that took a few resources.


The name might be a little confusing, but from what I can tell, that entry displays the sums of all the resources used by processes launched from executables that can no longer be found. You can test this theory by making a copy of a standalone program, running it for a while, then deleting it. The things it used will be added to the "Uninstalled processes" row.

Based on my Super User answer.

Saturday, October 29, 2016

AbiathRPC - Shared control of authentication challenge

A while back, I noted that it's less than ideal how an AbiathRPC server could order the client to sign anything the same length as a SHA256 hash. Putting the client in complete control of the message to be signed is also very bad, since that would enable replay attacks. I know I can't completely solve man-in-the-middle attacks without some sort of PKI, but I came to a good solution: have the server and client both be responsible for the signed message.

Now, the server still sends an authentication challenge for VeriMaps authentication, but the method that accepts the signed version now takes another part of the message in addition to the signature. When authenticating, the client generates a random bunch of bytes, appends that to the stuff received as the server's challenge, computes the SHA256 hash, and signs that.

Friday, October 28, 2016

AbiathRPC - Level downloading

A while ago in AbiathRPC development, I got the server to load levels from disk and transform them into something meaningful but also WCF-compatible. Today I got the client to download those levels and display them as though they were local. To do that, I had to write the level set proxy, which AbiathRPC swaps in when connecting to a server. It then clears the level view state dictionary (removing the image of the original temporary level), populates the level list in the Level menu, and updates the level label.

Server levels can be successfully viewed on the client. I am getting close to having some actual collaboration features working.

Thursday, October 27, 2016

Overlaying big text on the screen with PowerShell

Somebody wanted to use a command-line-invokable script to throw up a massive text overlay on the screen. The easiest way to do that using only built-in Windows tools is, of course, PowerShell.

When this script is run, the word "Hi!" appears in blue on top of everything. It goes away once the text (not the area around it) is clicked.

Add-Type -AssemblyName System.Windows.Forms
$form = New-Object System.Windows.Forms.Form
$form.TransparencyKey = $form.BackColor
$form.WindowState = 'Maximized'
$form.FormBorderStyle = 'None'
$label = New-Object System.Windows.Forms.Label
$label.Font = New-Object System.Drawing.Font ($label.Font.FontFamily, 200)
$label.ForeColor = [System.Drawing.Color]::FromKnownColor('Blue')
$label.AutoSize = $true
$label.Text = 'Hi!'
$label.Add_Click({$form.Close()})
$form.Controls.Add($label)
[Windows.Forms.Application]::Run($form)

It works by creating a standard Windows form, removing its background, maximizing it, adding a label with really large text, and showing the form.

Wednesday, October 26, 2016

AbiathRPC - VeriMaps authentication

A few days ago, I threw together an implementation of authentication for AbiathRPC based on VeriMaps certificates. Today I actually tested it, and I found that it didn't work: the data to sign has to be the same length of a hash produced by the hash algorithm used by the signature formatter. (Makes sense.) I changed the server to SHA256 the GUID before sending it to the client as the challenge. After fixing a couple simple oversights, VeriMaps authentication works as intended.

I considered whether a malicious server could get a client to sign an arbitrary blob of data (e.g. the SHA512 hash for a VeriMaps-signed level set). The choice of SHA256 for this hash algorithm makes it impossible for the server to use a level set's hash as the challenge. This setup is still less than ideal, since it precludes any other VeriMaps security systems that use SHA256. Therefore, I will change the server to always produce a challenge that starts with some constant value (e.g. "RPC") and change the client to check for that before signing. Nothing I do here can defend against man-in-the-middle attacks, but that's what real TLS is for.

Tuesday, October 25, 2016

Getting the Chrome version without it updating itself

Somebody wanted to know how to get the product version of Google Chrome without going to the "about" page, since that could cause an auto-update. I suggested a method that works on many programs including Chrome: consult the Details tab of the executable's Properties window. If the version was included by the program's author, it'll be in the Product version row. You can pull that from a running process by using PowerShell:

(Get-Process 'chrome').MainModule[0].ProductVersion

Monday, October 24, 2016

Determining whether the system was up at a given time with PowerShell, kind of

There isn't an easy cut-and-dry way of determining whether a Windows machine was running at a given time. You could try to look through Kernel-Power events and try to match "off"-like ones with "on"-like ones, but that would be tricky to get right with all the various power state transitions, especially if you consider sudden power losses.

Instead, I suggest this slightly subjective but very simple PowerShell oneliner:

Get-WinEvent -LogName Application | ? {$_.TimeCreated -le '10/19/2016 12:45 PM'} | select -First 1

It consults the Application event log (one of the very active logs) to get the most recent event before the given time. If that event's time is more than three hours or so before the given time, it's likely that the system was not running. If a human is reading the output, the contents of the most recent event would also probably provide a clue as to whether the system was powering down.

Based on my Super User answer.

Sunday, October 23, 2016

Setting the default prompt for command prompts

The prompt can be changed for the current command prompt window with the prompt command. If you want to persist the change, you need to set the PROMPT environment variable. This can be done from the command line with setx. This command sets the default prompt to a single > sign:

setx PROMPT $g

New command prompts will then have the new prompt. To reset the prompt, you can delete that environment variable with setx PROMPT "".

Saturday, October 22, 2016

Policy Plus - Acquire ADMX Files

The first thing Home users of Policy Plus will need to do is download and install the full set of policy definitions (ADMX files). These are free, but the installer from Microsoft doesn't place them in the PolicyDefinitions folder; the user has to move them there manually. To expedite this process, I added a feature to Policy Plus: Help | Acquire ADMX Files.

This dialog, given a destination directory (defaults to the main PolicyDefinitions folder), downloads that MSI from Microsoft, unpacks it (msiexec /a), and moves the ADMX files along with the current language's ADML files to the destination.


Once it's done, the success message lets the user open the newly downloaded policy definitions.

The changes are live on GitHub.

Friday, October 21, 2016

AbiathRPC - Server level loading

Before the AbiathRPC client extension can work with remote levels, the server has to be able to load and send them. A few days ago, I wrote a very simple addition to the server startup routine that opens a GalaxyLevels set with files specified in the config file and prepares it into a WCF-compatible format, which mostly involved transforming each level's data into a one-dimensional array as opposed to a three-dimensional one. I added a WCF operation contract to download all the levels, which will be called during the initial connection after authentication.

Thursday, October 20, 2016

Policy Plus - Semantic Policy Fragment

Over the past few days, I've been working on another aspect of the Semantic Policy System: the ability to easily produce a SPOL fragment from a policy's state. There's now a "Semantic Policy Fragment" option on the context menu of policies, which produces this dialog:


Just today, I found that there was no way to represent an empty multi-valued string in the SPOL format, so I made the None literal do that. I also saw that the value names in lists were always converted to lowercase when passed through PolFile, so I fixed that too. Finally, I added a check to PolicyProcessing that avoids a crash when Semantic Policy doesn't define all the elements in a policy.

The changes are live on GitHub.

Wednesday, October 19, 2016

AbiathRPC - Remote graphics

Today I managed to get remote graphics working in AbiathRPC. When the server starts, it loads two files as instructed in the config file into memory as byte arrays. When the tilesets are requested by a client, the server just sends down those byte arrays, which the client turns into bitmap images. To make Abiathar open an AbiathRPC level set, AbiathRPC supplies a very thin dependency file with the bare minimum needed for Abiathar to not crash. Abiathar first opens a blank level set with the Keen 4 graphics, then AbiathRPC replaces the graphics manager with one based on the two bitmaps received.

Next, I need to get a level set proxy going. That is made a little challenging by the fact that some Abiathar internals outside of the state manager modify the INextGenLevelSet directly. My current plan is to introduce a subtype of GalaxyLevel that carries a tag to uniquely identify the level on the server and identify levels newly created at the client.

Tuesday, October 18, 2016

Rebooting into Safe Mode from the recovery environment's command prompt

Today I worked on a Windows 10 machine that refused to boot. It could get to the recovery environment, but the "Startup settings" entry was missing, so I couldn't get to Safe Mode via normal means. It did offer a command prompt though, and some Googling turned up this Stack Overflow answer, which sets a flag in the BCD to boot to Safe Mode.

Note that in the recovery environment, {current} isn't the offline system's boot record. Instead, you can get the desired target's GUID from bcdedit -enum -v, then supply it to the command that sets the flag:

bcdedit /set {GUID} safeboot minimal

Reboot, and the system comes up into Safe Mode. Once you're finished fixing things, msconfig has a GUI that lets you go back to normal mode.

Monday, October 17, 2016

AbiathRPC - Injected state

A few days ago, I did some more tinkering with AbiathRPC. When I tried to overwrite the real state with the RPC-enabled wrapper, I immediately found that I had declared the field in Abiathar as being of the real implementation type, which meant that the new type had to be a subclass of that one. That actually made the job easier, since I only had to add methods for the overridden things as opposed to all of them. After fiddling with the order of arguments and the "this" object, I successfully injected the new state manager into Abiathar.

Then I threw together a basic WCF server, some simple authentication methods (username+password or open, VeriMaps still a work in progress), and some UI for the client to connect. The next step is to write some alternative implementations of the smaller wrappers. Then, I'll need to figure out how to finagle the dependency file opening process into opening something that's not entirely managed locally.

Sunday, October 16, 2016

Policy Plus - Export POL

Today I added an Export POL option to match yesterday's Import POL. For POL-file-based policy sources, the exporter just saves the existing PolFile instance to the new file. To export Registry-based sources, things are a little more interesting. Clearly, exporting the entire Registry would not be acceptable, and looking at every single policy to find the relevant Registry entries would also take a while (and miss some values if there were non-ADMX-based policies involved).

So I took advantage of the list of policy Registry locations I had already compiled. They were used to check whether a policy was really a policy as opposed to a preference. For each policy root, the exporter writes everything under it to a new PolFile, which is then saved to a file.

The changes are live on GitHub.

Saturday, October 15, 2016

Policy Plus - POL import

In continuing to fulfill the Policy Plus mission of providing convenient ways to share policy settings, today I wrote an Import POL feature. It's really simple: it just lets you browse for a POL file, asks you which section it belongs to, then applies it to the appropriate IPolicySource using the same method as the Save routine.

Next, I'll see about a way to export all currently-existing policy settings as a POL (in case the current source is a live Registry).

Friday, October 14, 2016

Policy Plus - Import Semantic Policy

Today I connected some UI to the Semantic Policy parser I finished yesterday. The form is essentially a basic text editor:


The Open File button produces a file browser dialog, then puts the contents of the selected file into the text box. The Reset button clears everything out of the text box except for the signature. The Verify button makes sure the text is a valid SPOL file. The Apply button actually applies the Semantic Policy information to the policy sources. This dialog is accessible under a new top-level menu, Share.

I rearranged the parser a little bit so that it could include the line where an error occurred in the exception. I also decided to put the section identifier (U or C) before the policy ID. That way, it's easier to scan and harder to forget.

The changes are live on GitHub.

Thursday, October 13, 2016

Policy Plus - SPOL parser

A couple days ago, I started writing a parser for a new Semantic Policy format. Today I filled out the part that loads the data for extra options. It figures out the type automatically, without needing to check the actual policy definition.

  • Enum selected indices are the number prefixed with the pound sign, like #2
  • Normal numbers are just the number, like 45
  • Checkbox check states are Boolean-naming strings, True or False
  • Text box contents are the string surrounded by single quotes with no escaping needed, like 'I can't do that'
  • Multi-valued text box contents are the double-quoted separated by commas, double quotes escaped by doubling if necessary, like "Thing 1", "I said ""wow!"""
  • Lists (non-dictionary) are double-quoted strings, one per line, surrounded by square brackets
  • Dictionary-like lists are the same as normal lists but with two strings on each line, one for the key, one for the value
An empty list and an empty dictionary look the same but are different types, so the parser just turns them both into Nothing, which is ignored by PolicyProcessing instead of causing an invalid cast.

Once I throw together a UI for importing SPOLs, I'll be able to test this parser.

Wednesday, October 12, 2016

AbiathRPC - State proxy

For quite a while, I've been thinking about creating an Abiathar extension that functions as a client for a server-client level editing collaboration system. The whole system would be called AbiathRPC, a play on words involving "Abiathar" and "RPC" (Remote Procedure Call). I had some extra time today, and I had an idea I wanted to test.

A lot of Abiathar's functionality is accessed programmatically through the IAbiatharState interface. For AbiathRPC to intercept the various calls, it would need to replace some functions on that interface. I don't want to manually rewrite the full implementation, which might change from version to version. I decided to try the Emit features of the Reflection system, which allows for runtime code generation.

I threw together a class that takes an IAbiatharState and uses it to create an AbiathRPC state wrapper. It generates a new class implementing that interface and (using the list of "hooked" methods) figures out where to redirect calls. The body of each generated method is very short, just a load of a field that stores the real state wrapper, a push of each argument, and a call. It took a lot of fiddling, but eventually I got something that works for the methods I tried (one pass-through and one hooked) and doesn't blow up with InvalidProgramException.

Tomorrow I'll see about swapping out the real Abiathar state manager for this one to make sure that the pass-through doesn't break anything.

Tuesday, October 11, 2016

Policy Plus - Semantic policy files

Sharing policy settings is a wordy affair at the moment. To tell someone how to tweak their machine in gpedit.msc, you have to step them through the right sequence of categories, have them hunt down the right policy, and twiddle the extra options as appropriate. .reg files make sharing Registry entries easy - there should be an analogy for policies.

Today I started work on just such a thing: the Semantic Policy format, .spol. Policy Plus will eventually have the ability to import (and probably create) these files. My goal is a format that's easily parsable, easily human-readable, and easily human-writable. It's not completely worked out yet, but I'm thinking of something like this:

Policy Plus Semantic Policy

Microsoft.Policies.BITS:BITS_Job_Timeout C
 Enabled
  JobInactivityTimeout: 5

Microsoft.Policies.BITS:BITS_MaxContentAge C
 Disabled

I plan on keeping indentation optional, but it does make the file easier to read, in my opinion. The enum type will be distinguished from the normal number type by a # sign before the number. String literals will have quotes. I'm not sure what to do about multiline string literals; I'm thinking of not supporting them at first because the UI doesn't (not in Policy Plus, not in LGPE).

This format will be superior to .pol in terms of policy representation because it actually has the semantics of policies; notice how there's no mention of Registry values.

Monday, October 10, 2016

Where Windows 7 stores pinned files and folders

In Windows 7, programs, files, and folders can be pinned to the Start menu. (For files and folders, the way of doing so isn't super obvious: you have to drag them from Explorer onto the Start button.) Programs that are pinned get shortcuts placed in a certain folder under %APPDATA%, but file/folder pins don't appear there.

So, to find where that information goes, I did some digging with Procmon. I found that Explorer keeps the pinned items in the values in this Registry key:

HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage2

The values of interest are Favorites, FavoritesChanges, and ProgramsCacheSMP. They're all binary, so changing them would be difficult. I did manage to replace a pinned folder with one with the same length of name in the same parent folder by changing all instances of the original target's name to that of the new target, but adding, removing, or significantly modifying an entry would be very difficult without reverse engineering the blob format.

Based on my Super User answer.

Sunday, October 9, 2016

Policy Plus - Info on the current category

For quite a while now, if you selected a category in the right pane of Policy Plus, that category's name and description would appear in the informational middle pane. Since Policy Plus doesn't have an Administrative Templates node to contain all the policy categories, though, there was no way to select one of the top-level categories to see its description.

That seemed strange to me, so I just adjusted the UpdatePolicyInfo method to show the current category's information if nothing was selected on the right. The subcategories-and-policies-count text now changes slightly ("This category" vs. "The selected category") depending on whether the category in question is selected from the categories tree or the category listing.

The changes are live on GitHub.

The top-level category "System" has its info in the middle pane

Saturday, October 8, 2016

Embedding a scrollable piece of plain text

I frequently need to paste code onto this blog that contains lines long enough that they might extend beyond the width of their container. By default, such lines would wrap, which would look strange for code. Therefore, I've taken to enclosing code in elements that have a horizontal scrollbar, as I did in a recent post.

This can be accomplished with a single element: <pre> for the code formatting, with the style element set to get the horizontal scrollbar:

<pre style="width:100%;overflow-x:scroll">Code here
More lines of code, no BR needed</pre>

The only disadvantage with this simple approach is that the scrollbar will always appear even if the text fits perfectly fine.

Friday, October 7, 2016

Windows 10 Wi-Fi won't turn on? Install different drivers

Today I dealt with a Lenovo ThinkPad E545 laptop that refused to enable Wi-Fi. In the network pop-up from the notification area icon, it said "Wi-Fi off." Flipping the appropriate switch in the Settings app had no effect; it just went back to Off immediately. Reboots didn't help, everything seemed fine in Device Manager, and no third-party VPN software (which is sometimes the cause of Windows 10 network troubles) was installed.

The only other thing I could think of was to install a different driver. Lenovo hasn't published Windows 10 drivers for the E545 yet, but I found some for 64-bit Windows 8. Bizarrely, they had drivers from at least two different vendors. The Realtek installer actually ran - as opposed to others which didn't. After setting the driver in Device Manager to the new Realtek one, the Wi-Fi switch actually worked, and sure enough, Wi-Fi turned on as normal.

Thursday, October 6, 2016

Moving data from PowerShell to a batch script

Sometimes getting a certain piece of data is dramatically easier in PowerShell than with the normal command-line utilities. If you've already written a script for batch, then it would be good to marshal data from PowerShell back into a batch variable.

That's moderately easy with PowerShell's Out-File and the command prompt's set /p. You do have to be careful with encoding: PowerShell by default spits out UTF-16LE files with a byte order mark, and set /p doesn't work well with that. The -Encoding switch has you covered.

This little fragment of batch scripting uses PowerShell to get the location of the user's Documents folder and stores it in a batch variable called DOCSPATH:

powershell -Command "[Environment]::GetFolderPath('MyDocuments') | Out-File 'docspath.tmp' -Encoding ascii"
set /p DOCSPATH=< docspath.tmp
del docspath.tmp

This only works well for data representable as text, but the command prompt doesn't really handle objects anyway, so that's OK. You do need write access to the current directory to run the above snippet; if that's an issue, change the file paths to point somewhere writable.

Based on my Super User answer.