Saturday, March 31, 2018

Keen Modding Live - Clone levels

Today I mostly implemented Abiathar Live Studio's Fork Level command. After pasting a version URL, the user can select a path for the ADEPS file. The development and test environments are downloaded and prepared as usual, then a pull is executed. Implementing this system turned out to be pretty easy thanks to having the smaller parts (ADEPS selection, environment setup, and pulling) already done. I have yet to implement the level search method of version selection - currently the user must paste an URL - but once that's done, forking will be easy.

Since it's now possible to have local copies of levels that one doesn't own, some assumptions about permissions will need to be reevaluated. As a start, I made the Level Properties window actually check for errors (mostly permissions problems) and complain about them after attempting to save.

Friday, March 30, 2018

Use VCF files to get SNP information from large data sets

Recently I needed to find information on the co-occurrence of some single-nucleotide polymorphisms in a human gene. For a small data set covering only the gene of interest, manipulating the information in SAM format worked well. But then I wanted to look at the data generated by the 1000 Genomes project, which is comprised of thousands of full genomes - a ton of data. My scripts probably wouldn't be able to handle files that large, and even extracting the relevant SNPs using my current tools from a single genome could take ages. Fortunately, the 1000 Genomes project also offers VCF files, which are catalogs of variations with each individual's type at that site right there on the same line. That's extremely convenient. The rsID is the third tab-delimited field, and filtering for rsIDs I needed was pretty easy with a bit of PowerShell.

Thursday, March 29, 2018

Trying to run only a dependent TestNG test may fail with "nonexistent group"

The IntelliJ IDE allows you to select a specific TestNG test to run. One person, attempting to run a test, received an error saying the test method "depends on a nonexistent group" even though the prerequisite group was definitely in the test suite. The problem is that IntelliJ doesn't include dependent tests in the impromptu battery of tests when preparing to run a specific test, so TestNG thinks the prerequisites don't exist and fails. Running the entire test suite works fine.

Wednesday, March 28, 2018

The Android Studio emulator doesn't work on AMD CPUs on Windows

Today I helped someone who was trying to use Android Studio's emulator but getting an error about virtualization capability: "Your CPU does not support required features (VT-x or SVM)." His CPU did support virtualization and it was enabled in the BIOS (Task Manager confirmed it); he did not have Hyper-V enabled to conflict with it. This was strange - it should have been able to virtualize just fine. Careful reading of a page on the emulator, though, revealed the problem: on Windows, their emulator only supports Intel virtualization for hardware acceleration! The person I was helping has an AMD processor.

He decided to just use a physical phone for testing. Other solutions include using the Visual Studio Emulator for Android, which is supposed to appear to Android Studio as a USB device. This is the strategy I'm using (since I have Hyper-V enabled already), but it took a lot of effort and fiddling to make it actually work.

Tuesday, March 27, 2018

When MATLAB shows side-by-side configuration errors

I recently tried to run a MATLAB compiled program that produced errors about the side-by-side configuration being incorrect. This was on an essentially fresh Windows 10 virtual machine, so there shouldn't have been too much junk interfering with anything. Some searching revealed that, apparently, a Visual C++ Redistributable update needs to be installed to correct the problem. The version installed needs to be of the right bitness for the application. The MATLAB program I had downloaded was ostensibly 64-bit, but seemed to have 32-bit components that required the 32-bit version of the Redistributable.

Saturday, March 24, 2018

Keen Modding Live - Get version by ID

I started the UI for selecting a level to clone/fork. I suspect it'd be most convenient for users to simply copy the URL right from the web page where they're playing the level, so there's a button to identify a version from the URL on the clipboard. While implementing that, I found that there was no way to get the information on a single specific version from the API, only to get the versions associated with a specific level. I adjusted the "get version" API endpoint to also accept a version ID and used that functionality to make the desktop client extract version information from the current level URL scheme.

Friday, March 23, 2018

FMod - Simultaneous Tileset doesn't get re-enabled

I noticed while testing Abiathar Live Studio that in Abiathar v2.10, Simultaneous Tileset gets disabled when opening a new project. This is a regression; the past, correct behavior was to put Simultaneous Tileset in its user-selected startup configuration when opening a project. I had moved a bit of code into the "only set up default settings if opening project for the first time" block to avoid toggling settings, but apparently Simultaneous Tileset gets disabled when projects close, so I should just put it back every project load.

Thursday, March 22, 2018

Keen Modding Live - Alternative controls

A Keen Modding user reminded me today that, on some browsers, the Alt key triggers some browser behavior even when keyboard input is supposed to be directed to the web app. This is a problem for Keen Modding Live, since the pogo key is Alt. The user suggested Z/X/C as an alternative to Control/Alt/Space. I went through the original games and generated configuration files (CTLPANEL.CKx, CONFIG.CKx, KDREAMS.CFG) with those key mappings and added some code to inject the appropriate one into the DOSBox instance if the user chooses. The player page now has an extra row of buttons by the difficulty selector, allowing them to switch between Control/Alt/Space and Z/X/C. Just like with difficulty, this preference is recorded in the user record for future level plays.

Wednesday, March 21, 2018

Keen Modding Live - Pull

An important feature of Abiathar Live Studio will be the ability to download and create a development environment for a level that exists on the web. This is turning out to be tricky, mostly because I'm not sure how to make the level-and-version selection convenient and flexible. A simpler subproblem is that of selecting and downloading a version of a given level, so I started by doing that.

I added a Pull command that allows replacing the local project's state (levels and base version ID) with that of a given web version. This is useful for rolling back or for fetching changes that were published from a different computer. It works well.


The "show approved versions only" checkbox toggles whether the list excludes other people's unofficial revisions.


Tuesday, March 20, 2018

Awaiting WinRT's IAsyncAction in PowerShell

A while back, I figured out how to get data out of an IAsyncOperation in PowerShell using no third-party assemblies. IAsyncOperation has a relative named IAsyncAction that represents an asynchronous operation that returns no data. Awaiting it requires a slightly different function:
Add-Type -AssemblyName System.Runtime.WindowsRuntime
Function AwaitAction($WinRtAction) {
 $asTask = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and !$_.IsGenericMethod })[0]
 $netTask = $asTask.Invoke($null, @($WinRtAction))
 $netTask.Wait(-1) | Out-Null
}

Monday, March 19, 2018

Policy Plus - Check state inversion fix

While using the Element Inspector tool to get the Registry equivalent of a policy for a Super User answer, I noticed that the default state row for a check box was incorrect. When writing the Element Inspector, I had apparently got the check state display backwards. The fix was easy: switch the texts displayed. It's live on GitHub and the Debug build has been updated (includes this change and the more significant ADMX loading improvements).

Policy Plus - Better ADMX loader

Today I finally got around to addressing this issue report, which pointed out the Policy Plus fails the entire workspace load upon hitting one problem. I added exception handlers to AdmxBundle so that it keeps track of problems but carries on. I could have just done this by making a list of error messages as strings, but it seems weird for the ADMX loader class to care about how its complaints are displayed to the user, so instead it returns a list of objects that represent the failures and expose some properties of them. They provide a ToString override that the main UI uses to show them, but other consumers of the class could do their own rendering. All uses of the ADMX loading functions from the main form are now wrapped in code that notifies the user of the specific problems.

These changes are live on GitHub.

Sunday, March 18, 2018

Third-party fingerprint readers may cause lock screen problems

Today I worked on a laptop that couldn't be logged into - entering the password just made the dots spin for a while and the user never got logged in. The machine happened to have some OEM fingerprint reader software enabled to allow fingerprint logons from the lock screen. I found while looking at a Task Manager instance brought up by replacing sethc.exe with a copy of cmd.exe that the Windows Biometrics service was using a lot of CPU. Stopping the service made the logon screen glitch out for a moment, then logging in using a password worked perfectly fine. Apparently the third-party fingerprint logon system is buggy.

Friday, March 16, 2018

Sorting by expressions in PowerShell

PowerShell's sort cmdlet can order items by a given property. Sometimes it may be helpful to order based on some expression in terms of each item that doesn't appear as a property on the objects. To do that, you can use custom properties. The syntax is a little tricky. Instead of a property name, supply @{e={ expression }}, where expression can use $_ to access the item under consideration. For example, this sorts $someStrings by the strings' second character:

$someString | sort @{e={ $_[1] }}

Thursday, March 15, 2018

Remote Server Administration Tools might install fine but not show up as a feature

Today I tried to get the Windows 10 Remote Server Administration Tools installed in a VM so I could test some PowerShell modules. The VM had Windows 10 1709, so I downloaded RSAT for that edition. The MSU installed just fine, but the optionalfeatures dialog didn't list Remote Server Administration Tools even after a reboot. Downloading the MSU for Server 2016 and trying to install it just produced an error saying the update was already installed. To my surprise, I soon after noticed in the Start menu that there were RSAT shortcuts marked as New! The install appears to have completed successfully -- the PowerShell module I wanted is available -- even though optionalfeatures still doesn't list the feature.

Wednesday, March 14, 2018

Setting the lock screen background with PowerShell

There's no simple Registry value holding the path to the image used as the lock screen background for a given user (not counting the policy one that only works on Enterprise/Education). To automate setting the current user's lock screen background, you can use PowerShell!
Add-Type -AssemblyName System.Runtime.WindowsRuntime
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
Function Await($WinRtTask, $ResultType) {
 $asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
 $netTask = $asTask.Invoke($null, @($WinRtTask))
 $netTask.Wait(-1) | Out-Null
 $netTask.Result
}
$tStorageFile = [Windows.Storage.StorageFile,Windows.Storage,ContentType=WindowsRuntime]
$img = Await ([Windows.Storage.StorageFile]::GetFileFromPathAsync($path) $tStorageFile
[Windows.System.UserProfile.LockScreen,Windows.System.UserProfile,ContentType=WindowsRuntime] | Out-Null
[Windows.System.UserProfile.LockScreen]::SetImageFileAsync($img)

The Await function used here appeared previously on this blog -- it allows PowerShell code to await and get results from WinRT tasks. The rest of the script is a straightforward application of the relevant WinRT APIs. First a StorageFile is opened from the $path specified, then it's used to set the lock screen image.

Tuesday, March 13, 2018

Finding the user profile path for a user in PowerShell

Windows user profile folders are not always named exactly the same as the SAM account name. This happens when there are collisions between local and domain accounts, but can also happen when there shouldn't be conflicts -- my laptop decided to tack on the first two characters of my last name even though the SAM account name for my Microsoft account is just my first name.

To get the user profile folder for a user identified by a SAM name, PowerShell scripts can do this:

$sid = (Get-LocalUser $UserName).SID.Value.ToString()
$profile = gwmi Win32_UserProfile | ? { $_.SID -eq $sid }
$profileFolder = $profile.LocalPath

If the Get-LocalUser cmdlet is unavailable (e.g. on relatively old versions of Windows), that first line can be replaced with another WMI query:

$sid = (gwmi Win32_UserAccount | ? { $_.Name -eq $UserName }).SID

Monday, March 12, 2018

Cleaning up if a PowerShell process gets terminated unexpectedly

One user wanted to have a Finally block in a PowerShell script run even if the script's execution was terminated by the End command of Task Scheduler. This isn't directly possible; no user-mode code will execute in a process once it's terminated. What is possible, however, is to start another script that waits for the original to exit (it'd need to be supplied the watched process's PID) and then performs any cleanup. If the cleanup should only happen in case of abnormal termination of the main script, the watchdog script's process can be terminated at the conclusion of the main script's work.

Saturday, March 10, 2018

Piping arrays to functions might not work as expected

PowerShell functions can include a Param block to gain more control over how they accept input. They can accept data from the pipeline by including a ValueFromPipeline parameter, for example. I found, however, that this tends not to work well with arrays. The function gets an array containing a single element: the first one in the original array. Using advanced functions could probably make accepting lists of things work better, but I found it easier to just accept the array as a normal parameter, which works as expected.

Friday, March 9, 2018

cipher /adduser says "access denied" if the files are read-only

Today I needed to allow a new user to access some EFS-encrypted files. Despite my account having an appropriate certificate and full access to the files, cipher /adduser said "access is denied" for each of them and couldn't add the user. Confusingly, performing the operation on new encrypted files worked perfectly fine. Eventually I ran some other mode of cipher, which gave a more helpful message indicating that the files were read-only. Apparently EFS won't allow certificate list changes if the read-only bit is set. Unmarking them read-only made things work as expected.

Wednesday, March 7, 2018

Policy Plus - Considering how to improve the ADMX loader

Today I did some experiments with the official Local Group Policy Editor to determine how Policy Plus should respond to problems with the ADMX complement. The LGPE rejects an ADMX as soon as it sees a duplicate ADMX namespace, while Policy Plus currently waits to fail until a policy object is duplicated. I think that's OK even though it might lead to some strange behavior; being more forgiving than the LGPE can't hurt as long as there's a warning that something bizarre might be going on. Policy Plus should definitely not fail the entire workspace's load when it hits this problem, though.

When it comes to missing ADML files, the LGPE fails the load of the corresponding ADMX. (Again, Policy Plus currently fails the entire workspace.) I think ignoring that one ADMX is reasonable; trying to continue using the display codes as the text would work for simple policies, but without the ADML, there's no way to arrange the presentations of extra options.

Tuesday, March 6, 2018

PowerShell assignment can unpack arrays into variables

I was surprised to learn a few days ago that PowerShell can assign multiple variables in one expression:

$a, $b = 1, 2

As expected, that puts 1 into $a and 2 into $b. It turns out such syntax works with nonliteral arrays on the right:

$numbers = @(1, 2)
$a, $b = $numbers

Having more variables on the left than there are elements in the array assigns null to the extra variables.

Monday, March 5, 2018

Intel wireless driver updates aren't delivered through Windows Update

For a while, I had wondered why my laptop's WiFi struggled to make any connections for a while after the machine resumed from sleep. Today I finally decided to check for a driver update. Nothing was available through Windows Update or the Update Driver feature of Device Manager. Googling the name of the Intel wireless device, however, brought up the downloads page, which had a new major version of the driver. Apparently it's entirely possible for there to be Intel driver updates without any notice through the Windows integrated delivery mechanisms.

Sunday, March 4, 2018

mklink needs the directory name available, not just an empty directory

One user was having some trouble with using mklink to redirect a folder to another drive. They had (seemingly) deleted its contents, but mklink still refused to make a link, saying that the filename was already taken. This is because mklink doesn't transform existing folders into junctions or symbolic links; it creates a new item with the given name. Deleting the existing folder should allow the creation of a new junction/link with that name.

Saturday, March 3, 2018

Any sequence of numbers can index a PowerShell array

It's moderately common to take a "slice" of PowerShell arrays by using a range inside the brackets, like $arr[0..3] to get a sequence of the first four elements. The .. syntax isn't special-cased in array indexing; you can use any expression that generates a series of numbers. Even pipelines are fine. If it's complicated, you might have to enclose the whole thing in parentheses. To get all the array elements at even indexes, you could do this:

$arr[(0..($arr.Length - 1) | ? { $_ % 2 -eq 0 })]

Assign 2 GB of RAM to Hyper-V machines before trying to upgrade Windows 10

Hyper-V has a dynamic memory feature that allows it to change how much RAM is allocated to the virtual machine while it's running. The absolute minimum - usually much less than will be allocated for realistic workloads - is set in the VM configuration. When starting the upgrade to a new build of Windows 10, the setup infrastructure checks whether the machine has at least 2 GB of RAM. If the check fails, it cancels the upgrade and deletes the update files. To avoid needing to wait for the update to be downloaded again, I'd advise making sure the VM is guaranteed 2 GB before trying to start the upgrade.