I’ve had Windows 10 installed for all of 10 minutes now, and I’ve already had to look up a tweak to get rid of an annoyance, OneDrive. I personally don’t believe in using the cloud to store my personal information. It’s just too easy to get hacked and stolen, and let’s not even talk about the NSA. I trust nobody.

Anyway, there are a couple things you can do to get rid of OneDrive from ever showing up. First is to stop if from auto-starting up. As with Windows 8.1, you can go to Task Manager, choose the Startup tab, and disable it there. It will still show up in Windows Explorer though. Happily there is a very simple fix, although it involves editing that nasty registry.

Open regedit in the usual fashion, and navigate to these two keys:



In each of these keys, there is the same DWORD key System.IsPinnedToNameSpaceTree. Change that key to ** from the default 1.

That’s it!

Big thanks to this thread for the information: https://social.technet.microsoft.com/Forums/en-US/7b18615f-2e81-46cb-bd11-d2035b7b015c/remove-onedrive-from-the-explorer-side-panel-in-windows-10?forum=WinPreview2014Setup

Sometimes you might have a server on a weak network link, or even a remote server with a slow connection. CommVault and other backup suites a lot of times will have difficulty dealing with these slow links and timing out. This is where the good ol’ robocopy program from Microsoft themselves comes in handy. Of course you can just run RoboCopy straight as a scheduled task, but you might want to get better tabs on what’s going on. One was to do this is through the PowerShell. It’s also a great script to get started with the powerful PowerShell and learn some basics. This script in particular backs up an entire partition (ignoring some system folders) which just hosted data to a centralized server and then e-mailed someone about the outcome and why. It also makes a log of everything it did, then keeps the logs in check so they don’t get out of control. Take a look, copy, paste, and enjoy!

#Function to define how to send an email. Must be available to the account used by the script.
function sendMail($message){
    #SMTP server name
    $smtpServer = "mail.domain.com"
    #Creating a Mail object
    $msg = new-object Net.Mail.MailMessage
    #Creating SMTP server object
    $smtp = new-object Net.Mail.SmtpClient($smtpServer)
    #Email structure
    $msg.From = "serverName@domain.com"
    $msg.ReplyTo = "serverName@domain.com"
    $msg.subject = "ServerName Backup"
    $msg.body = $message
    #Sending email

$logpath = "c:\log\robocopy-$date.txt"
$date = Get-Date -UFormat "%Y%m%d"
If (!(Test-Path $logpath)){ New-Item -ItemType file $logpath }
$timerun = Measure-Command {$process = Start-Process robocopy -ArgumentList "d:\ \\remoteserver\remoteshare /np /mir /mt64 /log:$logpath /xd 'D:\System Volume Information' 'D:\$RECYCLE.BIN' 'D:\RECYCLER'" -wait -NoNewWindow -PassThru}
$log = Get-Content $logpath -raw

if ($process.ExitCode -eq 0) {
        sendMail("Successful. Exit code 0. No files were copied. No failure was encountered. No files were mismatched. The files already exist in the destination directory; therefore, the copy operation was skipped. Backup completed in $timerun")
    elseif ($process.ExitCode -eq 1) {
        sendMail("Successful. Exit code 1. Backup completed successfully in $timerun")
    elseif ($process.ExitCode -eq 2) {
        sendMail("Successful. Exit code 2. There are some additional files in the destination directory that are not present in the source directory. No files were copied. Backup completed in $timerun")
    elseif ($process.ExitCode -eq 3) {
        sendMail("Successful. Exit code 3. Some files were copied. Additional files were present. No failure was encountered. Backup completed in $timerun")
    elseif ($process.ExitCode -eq 5) {
        sendMail("Successful. Exit code 5. Some files were copied. Some files were mismatched. No failure was encountered. Backup completed in $timerun")
    elseif ($process.ExitCode -eq 6) {
        sendMail("Successful. Exit code 6. Additional files and mismatched files exist. No files were copied and no failures were encountered. This means that the files already exist in the destination directory. Backup completed in $timerun")
    elseif ($process.ExitCode -eq 7) {
        sendMail("Successful. Exit code 7. Files were copied, a file mismatch was present, and additional files were present. Backup completed in $timerun")
    elseif ($process.ExitCode -eq 8) {
        sendMail("Warning. Exit code 8. Several files did not copy. Backup completed in $timerun")
    else {
        sendMail("Error. Backup did not complete successfully." + "`r`n`n" + $log)

#Now clean up log history so it doesn't get overgrown.
$Now = Get-Date 
$Days = "14"
$TargetFolder = "c:\logs"
$Extension = "*.txt"
$LastWrite = $Now.AddDays(-$Days)
$Files = Get-Childitem $TargetFolder -Include $Extension -Recurse | Where {$_.LastWriteTime -le "$LastWrite"}
foreach ($File in $Files) {
    if ($File -ne $NULL) {
        Remove-Item $File.FullName | Out-Null

I have many hobbies I dabble in, one of them is vintage computers, and the other is vintage phones. I have an Asterisk server with a special card that connect to some of my vintage phone gear. I also have vintage computers that I could use to play with modems and act as a phone company of sorts. Of course Asterisk is digital and that introduces some problems, but that’s another story for another article far far away. I have a server set up as a dial-in server (as in I can dial the server’s modem extension as it is connected to one of the ports of that special card mentioned earlier). I wanted to make a dial in server that can serve DOS and CP/M files, but not in a BBS form as I didn’t want or need the complexity of a full BBS system. Sure, there are a few downsides like someone could hang on the line forever if they wanted to. Being that this sort of thing is becoming more and more obscure, I’m not too worried about that. I am however worried about making it public and having someone come in and mess with and break the system. After some research I found some interesting software called jailkit. This does exactly what I needed. This is also useful for creating very restricted users on servers for other projects.

For example, my dial in user only has access to the XMODEM and ZMODEM commands that you can install in Linux, and CD to change directories. The jailed user can’t do anything else except change directories around in the jail itself, and transfer files the old fashioned way. Now, my usage case is pretty extreme (and probably a bit weird), but it’s a good example of how locked down you can get.

Before I begin, a huge thanks goes out to “gs69azza” and his forum post here. Most instructions I found on Google don’t work for the newer versions of Ubuntu. There was always something weird that would stop me in my tracks.

First, download and unpack the latest version of jailkit (the the time of this post, it is 2.17. Change the link as necessary to get the latest (see the jailkit link above):

cd /tmp
wget http://olivier.sessink.nl/jailkit/jailkit-2.17.tar.gz
tar xvfz jailkit-2.17.tar.gz
cd jailkit-2.17

Now, compile and install:

sudo make
sudo make install

Next, make a jail. You can really put it anywhere you would like but do not put it in /home. This will confuse yourself and jailkit.

sudo jk_init -v -j /jail ssh

Next create the new home directory environment for users:

sudo mkdir /jail/home

Create a group in the jail to link the users that will be made to a “users” group. Create /jail/etc/group and add this line:


After that, we need to create a jail user in etc/password so we can define the shell to log in to. This example uses “jailuser”, but of course you can name it whatever you would like. This is the first place you must edit when creating a new user for the jail. Edit /etc/password and add the user as below:


Now, create the same user you created above in the jail itself. Create /jail/etc/passwd and add the following:


Now that that is done, we need to edit the shadow to include the new user. Edit /etc/shadow and add:


Of course, change jailuser to whatever user name you would like.

Next is to change the password of the new user:

sudo passwd jailuser

Now that the shadow file has been updated, copy the shadow files so that the jail is synced with the system:

sudo jk_cp -v -f /jail /etc/shadow
sudo jk_cp -v -f /jail /etc/shadow-

Next create the new user’s home directory:

sudo mkdir jailuser
sudo chown 2000:100 jailuser

Now we will need to copy over commands that you will want your users to use in this jail. The post linked above has a much bigger list, but here are some examples for some basics:

sudo jk_cp -v -f /jail /bin/bash
sudo jk_cp -v -f /jail /bin/ls

Note: bash is required, but don’t worry, they can’t use the chroot trick to break out of the jail with the bash command. ls is optional.

Keep issuing similar commands to copy over the software you want the jailed user to run. For example, If you want them to edit files, you have to copy over an editor. The jk_cp script also copies over the libraries needed to run the programs. There are a couple special cases:

(optional) Create /proc in jail for ps to work:

cd /jail/
sudo mkdir proc
sudo mount -t proc none /jail/proc

(optional) Set permissions for sudo to work:

sudo chown root:root /jail/usr/bin/sudo
sudo chmod 4755 /jail/usr/bin/sudo
sudo chmod u+s /jail/usr/bin/passwd

That’s it! Now log in as that user and make sure everything works. Check out /var/log/auth.log if you are having any issues. For example, I had an extra space character after the shell path in /etc/passwd which was preventing log in.

There are many things you can do with this setup. For example, I created a .bashrc for my user (as root so that the user couldn’t edit it), and added the following lines to hide more of the system, and enable a “help” command which is a very simple script I created that just tells the user what they actually can do. It also customizes the command prompt they get.

shopt -s checkwinsize
shopt -u mailwarn
alias help='/bin/help'
PS1="\u@\W> "

Note: The “help” script is actually in /jail/bin/help. For things that are sitting inside the jail, the paths are as if /jail was the root. The help script also overrides the standard “help” command.

Also, to remove more system identification (and for other reasons), I completely disabled the standard MOTD system wide.

If you don’t want to do it system wide however, and want to disable the messages for the user, create .hushlogin in their home directory:

sudo touch .hushlogin

Finally, my last requirement was to be able to serve DOS and CP/M files so that it is possible to xmodem them over (great for recovering an old system). Of course, it would be silly to duplicate the files over just for the jailed user. However, you can’t directly mount an NFS share to the user jail either, but you CAN do a bind mount! I use autofs to automatically mount my NFS file server to a directory in /mnt on the dial in server. Then I use a bind mount in fstab to make the directories I want available to the jailed user. Here is an example of an entry in fstab that makes this possible:

/mnt/fileserv/data/Software/CPM /jail/home/jailuser/cpm     none    bind,_netdev    0       0

Note: _netdev is super important in this line, don’t forget it! If you don’t have fstab wait for the network to become available, and you reboot the machine, it will hang trying to mount those directories (ask me how I know!).

Note 2: Don’t forget to make the directories to mount to (e.x. /jail/home/jailuser/cpm).

You can go pretty far down the jailed user rabbit hole. The jailkit homepage has lots of great documentation for doing more with it.

In an earlier post, I showed you how to modify, change, or even disable parts of the big long MOTD (Message of The Day) that you get with default Ubuntu. Admittedly, some of the information is useful at a glance. I have a pretty good pulse on my own Linux servers (since there is only a couple), so I don’t really need or want the messages. So, after a quick Google search I found this post that describes disabling the message for SSH through PAM. It’s pretty simple.

Just edit /etc/pam.d/sshd and comment (using the # sign) the following two lines:

session    optional     pam_motd.so  motd=/run/motd.dynamic noupdate
session    optional     pam_motd.so # [1]

Save your changes, and you’re done! Now all you see when you SSH in is the last login time. Much faster.

In most Windows environments I’ve worked in, there is rarely any good documentation, especially documentation that tells you were service accounts are being used. This always presents a problem when you have to change the account’s password, or have to change the account all together. Getting tired of things breaking when this happens, I finally wrote a PowerShell script to go out and find these accounts.

This script connects to each machine listed in a text file or a specific Active Directory OU, and goes through each account you want to find. This is also useful to find old accounts to get rid of, or accounts that are in places they shouldn’t be. It then dumps the results in a CSV in the specified directory. It checks local Administrators group, MS SQL server if installed, Scheduled Tasks, and Services. The user account it is run under needs to have administrator rights to the machines being tested.

This requires PowerShell 4.0 or higher. Enjoy!

#Location of the Output file:
$OutputDir = "c:\temp\"
#Location of the user list (comma or line separated):
$UserListLocation = "c:\temp\userlist.txt"

#Location of the machine list (comma or line separated):
#$MachineList = c:\temp\serverlist.txt

#OR get servers by AD OU
If (!(Get-Module ActiveDirectory)) {
    Import-Module ActiveDirectory
$MachineList = Get-ADComputer -SearchBase 'OU=Servers,dc=test,dc=domain,dc=com' -Filter '*' | Select -Exp Name


If (Test-Path $UserListLocation){
    $UserList = Get-Content $UserListLocation
    Write-Host "User list was not found. Exiting."

#Function to grab the local admins from a machine
function Get-LocalAdmins{
    $group = Get-WmiObject win32_group -ComputerName $computerName -Filter "LocalAccount=True AND SID='S-1-5-32-544'"
    $query = "GroupComponent = `"Win32_Group.Domain='$($group.domain)'`,Name='$($group.name)'`""
    $list = Get-WmiObject win32_groupuser -ComputerName $computerName -Filter $query
    $list.PartComponent | % {$_.substring($_.lastindexof("Domain=") + 7).replace("`",Name=`"","\")}
#Function to get users from SQL
function Get-SQLAdmins{
    foreach($SQLSvr in $SQLServers){
        $MySQL = New-Object Microsoft.SqlServer.Management.Smo.Server $SQLSvr
        $SQLLogins = $MySQL.Logins
        $SysAdmins += foreach($SQLUser in $SQLLogins){
            foreach($role in $SQLUser.ListMembers()){
                $SQLUser | Select-Object @{label = "SQLServer"; Expression = {$SQLSvr}}, @{label = "CurrentDate"; Expression = {(Get-Date).ToString("yyyy-MM-dd")}}, Name, LoginType, CreateDate, DateLastModified
$Machine = ""
$IsInAdmins = ""
$IsInSQL = ""
$IsInTasks = ""
$Services = ""
$OutputFileName = ""
$ErrorOutputFileName = ""
#Go through and test each machine listed
ForEach($User in $UserList){
    $OutputFileName = $OutputDir + "Results-" + $User + ".csv"
    $ErrorOutputFileName = $OutputDir + "Results-" + $User + "-ERRORS.txt"
    #Clean up the directory if already used
    If (Test-Path $OutputFileName){
           Remove-Item $OutputFileName
    If (Test-Path $ErrorOutputFileName){
           Remove-Item $ErrorOutputFileName
    ForEach($Machine in $MachineList){
        $MachineAdmin = "\\" + $Machine + "\C$"
        If (Test-Connection $Machine -quiet -count 1){
            If (Test-Path $MachineAdmin -ErrorAction SilentlyContinue){
                Write-Host "$($Machine) connected."
                #See if specified user is in the SQL server on the machine (if present)
                $object = Get-WmiObject win32_service -ComputerName $Machine | Where {($_.name -like "MSSQL$*" -or $_.name -like "MSSQLSERVER" -or $_.name -like "SQL Server (*") -and $_.name -notlike "*helper*" -and $_.name -notlike "*Launcher*"}
                if ($object){
                    $InstanceInfo = $object | Select Name
                    ForEach ($Instance in $InstanceInfo){
                        $SQLInstance = $Machine + "\" + $instInfo
                        Get-SQLAdmins $SQLInstance
                        If ($SysAdmins.Name -like "*$User*"){
                            $IsInSQL = $True
                    $IsInSQL = ""
                #See if specified user is in the local admin group
                $UserList = Get-LocalAdmins $Machine
                If ($UserList -like "*$User*") {
                    $IsInAdmins = $True
                    $IsInAdmins = ""
                #Find services that uses specified user for login
                $query = "SELECT Name FROM Win32_Service WHERE StartName LIKE '%$User%'"
                $Services = Get-WmiObject -ComputerName $Machine -query $query
                If ($Services){
                    $Services = $Services -replace 'Win32_Service.Name=',""
                    $Services = $Services -replace '"',""
                #Find any scheduled tasks running as the user
                $TaskInfo = Invoke-Command -ScriptBlock {schtasks /V /query /FO CSV} -ComputerName $Machine
                If ($TaskInfo -like "*$User*") {
                    $IsInTasks = $True
                    $IsInTasks = ""
                #Prepare to export to a csv list
                New-Object -TypeName PSCustomObject -Property @{
                    Machine = $Machine
                    IsInAdmins = $IsInAdmins
                    IsInSQL = $IsInSQL
                    IsInTasks = $IsInTasks
                    Services = $Services -Join " "
                    } | Select-Object -property Machine, IsInAdmins, IsInSQL, IsInTasks, Services | Export-Csv $OutputFileName -Append -NoTypeInformation -UseCulture
                Write-Host "$($Machine): No permission to connect."
                Add-Content $ErrorOutputFileName -Value "$($Machine): No permission to connect."
            Write-Host "$($Machine): Unable to ping."
            Add-Content $ErrorOutputFileName -Value "$($Machine): Unable to ping."
    Add-Content -Path $OutputFileName -Value "`nFinished."