Citrix ShareFile Migration Tool, Drive Mapper and other rubbish.

(UKFast FastDrive is Citrix ShareFile rebranded and using a StorageZone at the UKFast datacentre.)

Frustrating is the word. It’s not a good start when even the basics are totally wrong and broken 🙁

Some other general ShareFile and SFMT problems:

  • SFMT misses files and folders.
  • It crashes every time you close it.
  • Setting up a migration and setting a schedule doesn’t seem to work properly and certainly isn’t intuitive, if working at all. I gave up.
  • Pausing / cancelling a transfer that you just set up but told to run on a schedule seems to kill the schedule or something. It basically just doesn’t work.
  • The metrics – ETA, number of items to do / done makes no sense (see above picture)
  • It says it supports Server 2008, but, along with the other tools, required Dot Net 4.6.2 which isn’t possible on Server 2008. So anybody moving from Server 2008 or SBS 2008 to ShareFile will have to use a workstation to migrate all the data.

So, you try plan b – some sort of File sync utility to the ShareFile mapped drive. This appears to complete, but nope, there’s 10 gigs of stuff still missing in ShareFile!

 

Further to this, the ShareFile Drive Mapper allows you to specify (via Group Policy) an AccountSubdirectory. You can set this to your main root SF Shared folder, e.g. ‘Data’. You would then think that the mapped drive would show the contents of this folder, but nope – even though the Drive itself shows with the label ‘Data’, when you click into it, you are shown a folder called ‘Data’. So it is showing the shared folder within the shared folder. It’s basically completely stupid and useless.

The only way around this I have found is to make the MountLocation something like %userprofile%\ShareFile , and run subst X: %userprofile%\ShareFile\Data in everybody’s login script.
In fact – it’s not even as simple as that (subst in the login script is a no-go). Instead, the login script must copy a script (e.g. sharefile.cmd) to “%appdata%\microsoft\windows\start menu\programs\startup”. This will then cause Windows Explorer to run the subst command in the correct user context.

sharefile.cmd looks like this:


@echo off
REM this causes the script to re-open itself, but minimised.
if not defined IS_MINIMISED set IS_MINIMISED=1 && start "" /min "%~dpnx0" %* && exit

net use t: /del /y
if not exist "%userprofile%\ShareFile" mkdir "%userprofile%\ShareFile"

:startloop
echo Waiting for ShareFile to mount at %userprofile%\ShareFile
ping localhost -n 2 >NUL 
if not exist "%userprofile%\ShareFile\Data" goto startloop

echo Doing Subst for drive T: to ShareFile folder
subst t: "%userprofile%\ShareFile\Data"

exit

 

None of this should be necessary – it’s pretty poor all round really. We’ll see how the go-live goes on Monday.

Update: The rollout was eventful and a followup to this post is forthcoming!

notes to self in case I forget: DriveMapper confirmed as a total fail by about midday of day-two. New files not appearing even 45 mins after creation by colleagues, even though saved ~20 plus times by the creator (as per version history in ShareFile web GUI – so we know the saves are making it up to the cloud, but the change notification to other clients is either broken or (could it even be? would they dare???) simply does not exist). Confirmed not caused by subst workaround. Users can’t create new folders because explorer’s default/initial temporary new folder name of ‘New Folder’ already existed, but wasn’t showing so explorer tried to create same folder as already-existing, instead of its usual trick of making a ‘New Folder (2)’. This resulted in an Access Denied error that made no sense. Citrix Files Beta (which isn’t even available to this customer but I happened to find it via a random popup at another customer) seems to: resolve the issue around mapping to a shared folder (no subst needed any more), and also in my testing seems to show up new creates/saves/deletes from one PC to another in near real-time (couple of seconds).. Should I be having to install beta software to make this thing work though? DriveMapper uninstall on win10 leaves behind explorer namespace, had to create a [-HKCU blah] reg file to delete it en masse, as well as undo all my previous logon script / subst work. Must also rant about the need to use Group Policy to customise anything worthwhile. The whole point of this is to become serverless/decentralised, yet I need to import the policy definitions, make policies (which I can’t do on server 2008 because the templates aren’t compatible with the group policy editor, so I have to install remote server admin tools onto a workstation), and *then* (sheesh) I can export the policy from the registry, to import onto non-domain-joined PCs, just so that Citrix Files Beta will mount ‘Shared Folders\Data’ to the letter T:
F.U.C.K.  .M.E.

Taking control of gadgets!

In my search for a nice display with housing for my datalogger project, I came across the Autool X50 and X60 OBD2 gauge / code reader gadget (pod and gauge style respectively).

I bought them, in the hope that there might be something usable inside – a recognisable display panel or controller or something. I’m not interested in the OBD or automotive aspects of these devices, because I have already built a separate, more rugged ECU datalogger. I just wanted a display, but what I really wanted, was a display inside a gauge. I’ve only been able to get my hands on the X50 so far. The X60 gauge style version is on its way from China.

What I found inside was a GigaDevices GD32F103RBT6, 2MB flash eeprom, an LM393 for K/L line, an NXP CAN bus transceiver, and with the help of the guys on the stm32duino.com forums, the TFT panel and its controller were identified.

After some experimentation, the key components are all working with stm32duino.

There was some trouble getting the TFT LCD going. It turned out that the pin used for the TFT RST was claimed by JTAG by default, and the pin used for TFT D/C (data/command select) was claimed by USB in the maple / stm32duino base code, so workarounds were needed for these things.

Also the display controller (ST7789V), whilst working great with the ILI9341_STM library, does require MADCTL_BGR changing to MADCTL_RGB in Adafruit_ILI9341_STM::setRotation(uint8_t m)

The discussion thread is here.

and here’s a happy picture. The MCU is clocked at 128MHz here, which increases the SPI clock from the default 18MHz to the 32MHz that you can see here.

Sage Accounts v22 (2016) will not open. Splash screen flashes by.

Another month, another half day wasted on Sage problems. I’ve had this problem at a few sites, mostly accountancy practices, some of which use ADM / Client Account Manager and multiple versions of Sage Accounts.

The fix was to find SDBDesktopUpdateInstaller.msi in %temp%\SageAccounts\Q3Update. Right-click -> Uninstall, and then Right-click -> Install.
You may need to install the v22 ‘May Improvements’ before this works. YMMV. I’ve had enough of Sage. I now advise my customers to move away as soon as possible. Report designer problems, updates not updating, emails not emailing, data service screwing up both file servers and end user machines by backing-up gigabytes of user profile data instead of just Sage data at 5pm every night, and now to top it off, Sage 50 Data Service isn’t even compatible with / supported on Small Business or Essentials servers. What market are they targeting exactly? Don’t forget Sage isn’t compatible with / supported on Office 365 either (a.k.a. you will be fobbed off and on your own when report designer emails break again). I look forward to the day Sage are a dead and buried legacy.

FYI last month a huge amount of time was spent on a Report Designer issue with Accounts v23. It appeared that the Data Source was locked to ‘SageLine50v13’, as the reports failed to run, citing that data source as being missing, and it was not possible to change the data source from SageLine50v13 in any reports either (the dialog box’s Save Changes button was not clickable). I told the customer that it looked like they might have restored reports from a v13 client which needed updating, or maybe to set the reports path to local rather than data files location. That didn’t work, so I advised they make use of their Sage Cover support contract, since I only charge this client £100 per month for mostly-everything IT service and support. Sage advised the client that the computer was corrupt and needed a full re-format and reinstall. Given that it was a new computer a few weeks earlier and had Sage installed from a new v24 ADM disk, I disputed this, but was nonetheless left to try to work it out. After 6 – 8 hours of pissing about, I happened upon this Sage article. I had searched for the term SageLine50v13 a week earlier and found nothing, so who knows when this article was published?

My advice to Sage users is that it’s a nightmare to support and very prone to failure. There are thankfully many alternatives available now. Xero works for me.

The two biggest mistakes Sage ever made in my opinion, apart from getting involved in ACT!, were to introduce the Sage Business Desktop / SBD central-launcher/common-platform/whatever-the-hell-it-is thing, and the SData service and its follow-ups. Neither of these things have been beneficial to the end user. Both of them have had a gigantic net-negative impact.

arduino rtc setter via serial terminal (vt100)

using putty on the terminal.


#include "RTClib.h"
DateTime now;
RTC_PCF8523 rtc;

void loop() {

  if (digitalRead(15) & millis() < 5000) { //enter setup mode if d15 pulled high within 5 sec of power on.
  Serial.print("\033[?25l"); // hide cursor
  Serial.print("\033[2J"); // clear screen & home

  while (digitalRead(15)) { // stay in setup mode while d15 kept high.
    now = rtc.now();
    Serial.print("\033[0;0H"); // cursor to line 0 col 0
    uint16_t year = now.year();
    Serial.print(year, DEC);
    Serial.print('/');
    uint8_t month = now.month();
    if (month < 10) {
      Serial.print("0");
    }
    Serial.print(month, DEC);
    Serial.print('/');
    uint8_t day = now.day();
    if (day < 10) {
      Serial.print("0");
    }
    Serial.print(day, DEC);
    Serial.print(' ');
    uint8_t hour = now.hour();
    if (hour < 10) {
      Serial.print("0");
    }
    Serial.print(hour, DEC);
    Serial.print(':');
    uint8_t minute = now.minute();
    if (minute < 10) {
      Serial.print("0");
    }
    Serial.print(minute, DEC);
    Serial.print(':');
    uint8_t second = now.second();
    if (second < 10) {
      Serial.print("0");
    }
    Serial.print(second, DEC);
    Serial.print("\n\rUse keys y, m, d, h, M, s to change\n");

    if (Serial.available()) {
        switch (Serial.read()) {
            case 'Y':
            case 'y': {
                ++year;
                if (year > 2099) {year = 2000;} 
                rtc.adjust(DateTime(year, now.month(), now.day(), now.hour(), now.minute(), now.second()));
                break;
            }
            case 'm': {
                if (month > 11) {month = 0;}
                ++month;
                rtc.adjust(DateTime(now.year(), month, now.day(), now.hour(), now.minute(), now.second()));
                break;
            }
            case 'D':
            case 'd': {
                if (day > 30) {day = 0;}
                ++day;
                rtc.adjust(DateTime(now.year(), now.month(), day, now.hour(), now.minute(), now.second()));
                break;
            }
            case 'H':
            case 'h': {
                ++hour;
                if (hour > 23) {hour = 0;}
                rtc.adjust(DateTime(now.year(), now.month(), now.day(), hour, now.minute(), now.second()));
                break;
            }
            case 'M': {
                ++minute;
                if (minute > 59) {minute = 0;}
                rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), minute, now.second()));
                break;
            }
            case 'S':
            case 's': {
                ++second;
                if (second > 59) {second = 0;}
                rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), second));
                break;
            }
        }
    }
   }
  }
}

network folder listing very slow with Windows Explorer especially over VPN

I had a directory with ~2,500 subdirectories in it.
Viewing the folder with Windows Explorer on the LAN was a bit slow.
Viewing the folder over VPN was very very slow.

I thought this was an SMB version issue with the Server 2008 (not R2) machine, i.e. it not being very VPN friendly (VPN was my issue.. nobody notices it’s a bit slow on the LAN), and I was attempting to in-place upgrade it to 2012 as an interim to 2012 R2 (another story..)

I had tested a similar directory tree on a Server 2016 machine and it was rapido. I simply used xcopy to copy the directory structure without the contents, and used this to test.

So I was all set to upgrade the OS, get a shiny new SMB3, and …

Well the upgrade isn’t happening (component based servicing mess. This machine has had hundreds of updates on it since 2009.. nearly 9 years of updates have to be jigged about just so that Terminal Services Gateway role can be removed to allow the upgrade to Server 2012, and it’s just not happening.)

Anyway! I found out what was wrong. This is a little obscure.
About 900 folders in there had the +s attribute set! (System).

The quick clue was that ‘dir’ from a command prompt only listed about half the folders that were known to be in there.

I believe this was something I was asked to do ages ago, so that the company could make use of the ‘Comment’ field in windows explorer for folders. So I made a setComment script that tied into the explorer context menu, and read a message from you, then stored it in a Desktop.ini within the folder, and set the folder +S. It never got used because Explorer was flaky about displaying the comments.
The +S attribute makes Windows Explorer look into each folder for a Desktop.ini and process it.

So, my fix was as simple as:

for /d %a in (*) do attrib -s “%a”

(in the folder with all the subfolders).

Now it’s SUPER RAPIDO!

Arduino Zeitronix reader / logger

Not quite logging to SD in this code.. that part is in there but is not in use. Still working on KWP2000 & Zeitronix. Zeitronix bit is done and working well.

Here’s the Arduino / C++ code for capturing the Zeitronix stuff. I’m not bothering with the 3 byte start sequence in the output

#include 
#include 
#include 
#include 
#include 
#include 

const int chipSelect = 10;
int gotPacket = 0;
char packet[11];

void setup() {
    // Open serial communications and wait for port to open:
  Serial.begin(115200);
  Serial1.begin(9600);
  Serial1.setTimeout(100);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.print("Initializing SD card...");
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

}


void getZeitronixPacket(char* packetpointer){
gotPacket = 0;
char buffer[32] = {0xF}; // buffer 32 bytes to make sure we find the 3 byte start sequence.
  for (int i=0; i<32; i++){
    Serial1.readBytes(&buffer[i],1);
    if (i > 1 && buffer[i] == 2 && buffer[i-1] == 1 && buffer[i-2] == 0) {
          gotPacket = 1;
          Serial1.readBytes(packetpointer,11);
          return;
    }
  }
}


void exampleStuff() {
  // make a string for assembling the data to log:
  String dataString = String(millis()) += ",";

  // read three sensors and append to the string:
  for (int analogPin = 0; analogPin < 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
    if (analogPin < 2) {
      dataString += ",";
    }
}

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
}

void loop() {
char dataString[80];

while (Serial1.available() > 32){ // wait til there's a nice chunk in the serial buffer
    getZeitronixPacket(packet);
    // this would be our logtosd() below:
    if (gotPacket == 1) {
      sprintf(dataString, "%lu,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", millis(),packet[0],packet[1],packet[2],packet[3],packet[4],packet[5],packet[6],packet[7],packet[8],packet[9],packet[10]);
      Serial.println(dataString);
    }
}

// Serial.print(".");


}

KWP2000 fmt byte deciphering

It’s all in the docs, but it sure does help to write it out..
This is the first byte, the Fmt byte. Use it to know how much data there is to capture.

0 = optional length byte present, no address bytes
1 to 3f = subtract 0 to get the length, no address bytes

40 = optional length byte present, ?? address bytes unsure [exception mode (CARB)]
41 to 7f – subtract 40 to get length, ?? address bytes unsure [exception mode (CARB)]

80 = optional length byte present, address bytes present [physical addressing]
81 to bf – subtract 80 to get length, address bytes present [physical addressing]

c0 = optional length byte present, address bytes present [functional addressing]
c1 to FF = subtract c0 to get length, address bytes present [functional addressing]

Length = service id bytes (included) to checksum (not included)
Checksum = All bytes except the checksum itself, sum, mod 256.

edit: since writing the above, I have come to understand bitwise operations. Hey, I’m new to this programming stuff! I’ll re-write it soon. Rather than ‘subtract xx’, it makes more sense to deal with it as a series of bits and use bitwise & operators on it. e.g. bitwise & 0x3f for example would tell us if the two most-significant bits were set.. (0x3f being 00111111.. bitwise & 0x3f with 11xxxxx (x being anything) would return all 1s i.e. TRUE).

Datalogger for zeitronix zt-2 wideband afr plus obd2. Arduino adafruit feather m0 circuitpython

Code for https://youtu.be/b3TxFYFKEt0
This is CircuitPython. I have since re-written it in Arduino Wire (C++), and am now working on the KLine KWP2000 element of the project.

import board
import busio
import time
import adafruit_sdcard
#import adafruit_pcf8523
import microcontroller
import digitalio
import storage
import os

switch = digitalio.DigitalInOut(board.A5)
switch.direction = digitalio.Direction.INPUT
switch.pull = digitalio.Pull.UP

#Zeitronix Packet format, bytes[]
#[0] always 0
#[1] always 1
#[2] always 2
#[3] AFR
#[4] EGT Low
#[5] EGT High
#[6] RPM Low
#[7] RPM High
#[8] MAP Low
#[9] MAP High
#[10] TPS
#[11] USER1
#[12] Config Register1
#[13] Config Register2

#led = digitalio.DigitalInOut(board.D13)
#led.direction = digitalio.Direction.OUTPUT

SD_CS = board.D10
# Connect to the sdcard and mount the filesystem.
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
cs = digitalio.DigitalInOut(SD_CS)
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")

uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10)

#date = rtc.datetime() # will use this for the filename
# this board doesn't seem to have enough ram for the rtc library & sd & everything else going on here.. getting an allocation error
#filename = str(date.tm_year) + "-" + str(date.tm_mon) + "-" + str(date.tm_mday) + "-" + str(date.tm_hour) + "" + str(date.tm_min)
filename = "2017-09-11-test"
filename += ".csv"

def getPacket():
	rcdbyte = [None] * 3
	packet = [0] * 15
	packet[0] = time.monotonic()
	i = 0
	while True:
		rcdbyte[i] = uart.read(1)	#read a single byte
		if rcdbyte[i] == None:	#if we got an empty byte, assume the serial link is down, and return zeros.
			return packet
		if rcdbyte[i] == b'\x02' and rcdbyte[i-1] == b'\x01' and rcdbyte[i-2] == b'\x00': # we got our 3 bytes in order for the start of packet
			packet[1] = 0
			packet[2] = 1
			packet[3] = 2

			for x in range(4, 15):	#get the rest of the packet.
				byte = uart.read(1)
				if byte == None:	#if we got an empty byte, assume the serial link is down, and return zeros.
					packet[x] = 0
					return packet
				packet[x] = byte[0]
			return packet
		i += 1
		if i == 3:
			i = 0

#this is currently configured so that you have to short the pin to ground momentarily to start logging, then again to stop.
while True:
	if switch.value == False:
		time.sleep(0.2)
		f = open("/sd/" + filename, "w")
		while switch.value == True:
			packet = getPacket()
			f.write('{}\n'.format(packet))
			print('.',end='')
		f.close()
		time.sleep(0.2)

Remote Desktop printer driver name mismatch

Years ago.. about a decade ago, we used to use some kind of .ini or .inf file to tally up mismatched printer driver names between client & server when using Terminal Services printer redirection.
It’s long winded process, and I can’t really find any information on how to do it now. I did eventually find the information about a month ago, but it wasn’t easy to find, and when I looked at it I decided I just wanted to go home.

This problem is beginning to occur more frequently again now between Windows 10 and Windows 7. The situation is a Windows 7 Professional computer in the office, and a Windows 10 computer at home, trying to use Remote Desktop to access the Windows 7 computer.

Both HP and Dell, have different names in their Windows 7 drivers vs. the Windows 10 drivers.

So when faced with the same problem again today, I tried a different fix, and it seemed to work just fine.

I changed the driver name in the registry, restarted the Print Spooler, and the name changed in the drivers list. I disconnected / reconnected to Remote Desktop, and the printer redirection worked as it should.

As you can see in the pictures below, the key itself just needs renaming under HKLM\SYSTEM\CurrentControlSet\Control\Print\Environments\Windows x64\Drivers\Version-3 (or whatever for your specific driver).

In the screenshot below, I am adding “GDI” to the end of the “Dell B1165nfw Mono MFP” driver name, so that it matches with the new Windows 10 laptop that the person is connecting from.

Here’s the driver name on the Windows 7 Pro RDP host computer at the company:

Here’s the driver name on the Windows 10 client RDP client:

and here is me altering that name back on the Windows 7 Pro computer. I have added ” GDI” to the end, so that the names match.
The print spooler service needed restarting for the updated name to appear.

Prevent server from rebooting *before* remote logon

You’re at the logon screen. The server says “Automatic restart will occur today”. If you log on, it will either restart now, or when you’re finished, and you’ll get some support calls when it’s down!

From your favourite remote support tool, run the following command *before* logging on:

reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU /v NoAutoRebootWithLoggedOnUsers /t REG_DWORD /d 1 /f

If you leave the password prompt (click back to the Ctrl-Alt-Del screen), and then go back to log on, you should see that the “Automatic restart will occur today” part of the warning is gone, and you can safely log on.