PowerShell: Disconnecting Users

What often gets old is when people disconnect from servers and leave files and folders locked, that could affect a release run.

nb: This isnt 100% pure powershell, but I am using powershell to perform the loop behaviour needed

foreach($item in (query user /server:$env:COMPUTERNAME 2>&1 | select -skip 1))
    $sessionId = ($item -split "\s+")[-5]
    Write-Verbose "Logging Off Session: $sessionId"
    logoff $sessionId /server:$env:COMPUTERNAME

query user /server:[Machinename] queries for user sessions, both connected and disconnected.

$env:COMPUTERNAME targets the current machine, you could pass a known machine name to the query.

2>&1 downgrades errors to information

This deals with any session, so even those currently connected, which adds even more fun!

tools: I cannot spell or do grammar good!

I don’t think that I write that well, and I generally just type and type until something looks ok, then I have to go back and review what I have typed to make sure it makes sense, using a tool like Grammarly helps with that.

It doesn’t improve your writing but it does clearly show up any spelling mistakes or grammatical errors, the spelling mistakes will provide a well thought out list of options, and for me, it is clear enough that I can leave it and come back to it later. This I feel allows me to carry on with just typing out my ideas and then going back and reviewing the clear violations of the Engish language that I have just put on a page.

I often find myself right-clicking which is the default behaviour for the Chrome spell checker, but I am getting used to the left click actions they provide.

With WordPress with chrome extension

I have sometimes noticed that the choice I make isn’t always selected, so it sometimes takes an extra go to get it to apply the grammar police correctly. I also think it might be the refresh rate of the sites I use that don’t understand that I have changed something.

Other options

Grammarly also comes with some extras that you can add to office and word, chrome, and just as a stand alone desktop application.


It doesn’t make me write better, but I think it gives me more freedom to just type. I actually used it on this blog post!

PowerShell: Setting up a Register-ScheduledJob

Let’s look at something that I did, I needed to keep an eye on all the recycle bins on a server, that was a separate problem, but I wanted to schedule the job to occur once a week.

Just in case you are interested the script to do the recycle clean looks like this

$Shell = New-Object -ComObject Shell.Application
$Global:Recycler = $Shell.NameSpace(0xa)

$Global:Recycler.Items() | Remove-Item -Recurse

Register-ScheduledJob requires a ScriptBlock, so this becomes

$scriptBlock = {
$Shell = New-Object -ComObject Shell.Application
$Global:Recycler = $Shell.NameSpace(0xa)

$Global:Recycler.Items() | Remove-Item -Recurse

I then needed it to run in an elevated state, so I needed to set some options.

$options = New-ScheduledJobOption -RunElevated

Then I wanted a trigger to run every Monday at 7 AM.

$trigger = New-JobTrigger -DaysOfWeek Monday -At 07:00 -Weekly

I’ve also had to have one trigger every hour

$trigger = New-JobTrigger -Once -At "2017-07-14" -RepetitionInterval (New-TimeSpan -Hour 1) -RepetitionDuration ([TimeSpan]::MaxValue)

And then you wire it all together.

Register-ScheduledJob -Name "Recycle Cleaner" -ScriptBlock $scriptblock -Trigger $trigger -ScheduledJobOption $options

PowerShell: $array.ForEach({})

In the beginning, there was a cmdlet…

Most times, when you think about writing something in PowerShell, you will usually find within the first lines a Get-ChildItem, you will then inevitably have a for each loop.

Normally I would write this as foreach($item in $items), but on one occasion the autocomplete came up on the array variable with a .ForEach option, I didn’t know the correct use of this so I tried the usual

Get-Help ForEach -Examples

Get-Help ForEach -Online

As this didn’t really show this option (to be honest I may have not gone to the right help from PS) so I googled the same thing, which initially took me to a similar page on ss64.com, but they provided a link to other ForEach options, one of which contained how to use the ForEach (Method)

How to use .ForEach

let’s see if I can explain it in code:

# This exposes the $_ object, but I find that it doesn't know what each item is.
# So I often find myself setting that to a new variable.
$item = $_
#I guess as you learn more and more you become versed in the ways of the object and can free type out the properties you need.

As you can see, this form of writing a ForEach still allows a multiline statement, and as long as you know what properties you are after you never have to set the $_ object (but I know I will).

Beware of Dragons

There is something to be aware of in PowerShell version 3. If the $array could be null, you need to put in a check for that before doing your actions.

if($items -ne $null)

If you have used PowerShell 2, you may be aware of this problem with arrays already.

In PowerShell 3 and above the foreach loop handles null array objects automatically, but it won’t be until you use PowerShell 5 that the ForEach method handles null arrays.

So… do I like it?

This is a valid alternative to foreach($item in $items), but trying to provide a preference for one or the other is too close to call, but I will probably use it every now and again without concern.

devlife: The Netflix Culture

I’ve been listening to a podcast called Masters of Scale with Reid Hoffman

Reid Hoffman was the founder of LinkedIn (Interestingly I believe I am 4 degrees of separation away!).

In Episode 8 Reid talks to Reed Hastings from Netflix, they mentioned Netflix’s culture deck, so I thought I would take a look.

There is an older version on SlideShare, this also links to a more up-to-date one on the Netflix job website. I found the SlideShare one easier to read (but is obviously a bit out of date). The job site version was easier to steal quotes from, sorry plagiarise, sorry I mean reference.

Initially this deck was shown to new hires on their first day, but they soon learnt it best to be sent it out to prospective candidates, as they might not fit with the culture and dealing with that after hiring someone was very expensive.

Netflix have spent a lot of time working on this document (I believe it is still being evolved to this day), to be clear enough for anyone to follow; this is possibly why they posted this external, this isn’t something that should be a protected company secret, this is something that companies who work in the Software Development should aspire to.

I’ll just add the beginning; I could happily write the whole thing out, but I hope this might entice you to go off and read the rest.


We connect people with stories. Lots of people, and lots of stories. Our hundred million global members are a good start, but someday, we hope to entertain everyone. Entertainment, like friendship, is a core human need. No matter how big or small, dramatic or satiric, entertainment stimulates us, changes the way we feel, and gives us common ground.

Our culture is how we work together as employees to serve our members and grow. Our culture has been instrumental to our success and we keep improving it; our culture helps us attract and retain stunning colleagues; our culture makes working here more satisfying.

Like many companies, we strive to hire the best and we value integrity, excellence, respect, and collaboration.

What is unique and special about Netflix is how much we:

  • encourage independent decision-making by employees
  • share information openly, broadly, and deliberately
  • are extraordinarily candid with each other
  • keep only our highly effective people
  • avoid rules

Our core philosophy is people over process.

More specifically, we have great people working together as a dream team. With this approach, we are a more flexible, fun, inventive, stimulating, creative, and successful organisation.

This is an interesting opening, and flows thought the rest of the culture document.


They go on to list specific values that DON’T SPELL OUT A WORD! that is amazing, all too much things must spell out a word (unless JCCICPSIII is a word?).

This culture needs YOU

The bullet points all start with You, this doesn’t feel like someone forcing the company’s will on you else it would say The Company wish it that you, by simply saying you they play on the psyche a bit, the culture comes from you; you work for us, but these point are what we expect from you; if you can follow and behave like this (see bullets) you will be working with like-minded people, work well with other people at our company and you will enjoy your work.

We, not I

They work on the WE rather than the I, it is all very well and good to see the I, but as the saying goes, there is no I in team (there is a ME, but definitely no I). People can be the most brilliant software developer in the word, but if they don’t fit the culture they won’t get employed.

Work like a Sports Team

They use an analogy to describe Netflix as a sports team, rather than a family and use internal collaboration to drive external competitiveness. “For teams that succeed, there is often warmth between players, so this culture emphasising those aspects, when people come in the team will help them, but it is about performance, where as a family is about unconditional love.”.

How to end this post…

To be honest I am not sure how to finish this post, I am not going to be providing any TLDR version of the culture doc, as I think what they have written is quite a succinct document. I cannot think of anything very poignant that isn’t covered really well by the culture document itself, so I think I will just say go read it now, if you haven’t already.

git: Adding an alias to git for a repository refresh

When working with git, I find myself doing a lot of the same requests, by creating an alias I reduced my keystrokes.

The longhand

git fetch --prune

git reset --hard origin/[branchname here]

git clean -dfX

git clean -dfx

so, I created an alias

I have this added this to my .gitconfig file found in Users/[loginname].

refresh = !git fetch --prune && git reset --hard origin/$(git rev-parse --abbrev-ref HEAD) && git clean -dfX && git clean -dfx

Since writing this post I have been getting conflicts within the .vs folder, so that forced me to modify the refresh script.

refresh = !git fetch --prune && git reset --hard origin/$(git rev-parse --abbrev-ref HEAD) && git clean -dfx -e '.vs/'

$(git rev-parse --abbrev-ref HEAD) works against your current branch and finds the related branch name, in theory, you have a remote branch with the same name.

the 2 git clean calls do slightly different things.

d,f,x and X are arguments on git clean, I could probably just do git clean -dfxX (not sure), but I created the script to reflect what I normally type. (update I checked you cannot do xX).

Remove untracked directories in addition to untracked files. If an untracked directory is managed by a different Git repository, it is not removed by default. Use -f option twice if you really want to remove such a directory.

-f –force
If the Git configuration variable clean.requireForce is not set to false, git clean will refuse to delete files or directories unless given -f, -n or -i. Git will refuse to delete directories with .git sub directory or file unless a second -f is given.

Don’t use the standard ignore rules read from .gitignore (per directory) and $GIT_DIR/info/exclude, but do still use the ignore rules given with -e options. This allows removing all untracked files, including build products. This can be used (possibly in conjunction with git reset) to create a pristine working directory to test a clean build.

Exclude, this basically allows you to define an exclusion to ignore after applying -x.

Remove only files ignored by Git. This may be useful to rebuild everything from scratch, but keep manually created files.

if I’d left the git clean -dfX the whole git clean -dfx -e '.vs/' would be pointless.

If you don’t need or want the full functionality the alias can be adapted to each person on a machine suit their needs.


So now, all I need to do to activate the process is git refresh and because I added this to my global git config it is available on any git repository on my machine.

I am expecting some convention, such as you are working against a remote called origin and your remote branch has the same name as your local, but it does save me keystrokes.

git-tfs: The Gitification Project

More to follow

I have another post planned that I am working on, that will go into a bit more detail about the fun that can be had with git-tfs, but for now, I will just provide a reference to the git-tfs site.

Basic Brief

I was asked to setup a transfer for some of our tfvc sources to git. I was already quite up to speed with what git-tfs would allow you to do, but this was an experience to flex and expand on what I already knew.

I began with a basic setup, which connects to the beginning of the branch and then steps through the entire history and added the desired new home.

$env:Path = $env:Path + ";C:\tools\gittfs"

cd C:\g

$tfbranch = "$/Project/Product/Main"

$work = "Product"

$git = "http://tfs.domain/tfs/Collection/Project/_git/$work"

git tfs clone http://tfs/tfs/Collection $tfbranch $work

cd $work

git remote add origin $git

After this initial setup, I created the new repository and pushed the branch. I had a colleague setting up the builds so we would address any issues after comparing the sources.

But that was a one off, I needed the process to continue when a new commit was made. The behaviour I wanted was; on new commit, get the latest version and refresh the branch, push the new head to the new git repository.

Automation of the process

The process of creating a scripted process was relatively straightforward.

The first event was to checkout the current branch and perform a fetch against the tfvc source, the head of the local branch was then applied with a hard reset and the subsequent changes pushed to the new origin.

In script form I had the following, the arguments passed in were
%1 = local branchname / git remote branchname
%2 = source local copy location
%3 = git-tfs tfs remote branchname

cd E:\gittfs\%2

SET PATH=%PATH%;E:\tools\gittfs

git checkout %1

git tfs fetch -l

git reset --hard tfs/%3

git push origin %1

git push origin --tags

Some pitfalls to be aware of

  1. I was initially looking at using PowerShell for the automated script, but the output from git was returning an error to the PowerShell console, even on success. so I went with command line, with the downside being, you don’t get any errors reported at all!

  2. When you perform git tfs fetch it will start at the last known point and find the subsequent steps if a branch was deleted and a new one created with the same name, it will not jump to the new start and track any changes beyond the point it was deleted. This can be fixed by checking the commit number of the next stable point you want to reference and calling git tfs fetch -c[commit number]

  3. For some reason or other, I had a commit on one history being completely missed off, which created a different future of the git repository versus the original tfvc. I needed to replay the history from a known commit and overwrite the history up to the latest check-in. This was possible by doing git tfs fetch -c[commit number] --force. If you don’t use force all the commits will effectively duplicate on the head of your current branch.

  4. If you do want a bridge between the 2 version, and not just a 1-way sync, you do need to make sure that your branch on tfvc is a branch and not just a folder, you will get a warning to that effect.


I am quite surprised by what I was able to do, in such a short time, something I thought was going to cause a lot more trouble wasn’t half the issue I thought. There do appear to be some little gotchas that you need to be aware of, which I listed above, but other than I was able to fulfil the brief with the git-tfs tooling.