BGINFO - A Posh Recreation
Recently I have been building a lot of Windows Servers in different environments - one
Grumpy Admin isn’t grumpy today, he is freaking fuming. Personal Life, meh! If only life came with MAN pages
Get-Help Life
The internet in the office is also totally broken at the moment, it is slower than dial-up modem. Personally, I find there is a correlation to the when the guy the other side of the office arrives and leaves and the quality of the internet. I suspect he might be streaming youtube or P2P. It was actually faster to cross the room and look out the Window to get the local weather than to use Google it! Seriously, first world problems.
Slow Internet makes me grumpy, but sometime slow can be your friend… Sometimes there are things you want to download, that you are not in a hurry for like the preloading of ISO’s or VHD’s, so why max out your bandwidth and degrade your experience of Dilbert and XKCD. Throttling downloads can be useful.
Wouldn’t it be nice if there was a method in Windows to transfer files intelligently and in the background? Also wouldn’t it be really good if this was all exposed to PowerShell in easy to use and understand cmdlets.
Well let’s not bite at the BIT for this <Sorry the pun had to be done>…. Most administrators would have and should have heard of BITS “background intelligent transfer service”. This is the delivery method we are used when it’s “that time of month” when Windows machines get their
So lets today have a quick look at BITS
Let’s head over to MDSN – I prefer the MSDN pages on BITs are they are bit grittier and are a bit more useful if you want to understand technically how BITS works. As we know we are going to be taking a programmers approach rather than an administrative approach, when we are starting to create scripts that creates Jobs and Tasks, and have to have error handling.
https://msdn.microsoft.com/en-us/library/bb968799%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
I like to have a goal, something to achieve otherwise we are coding for nothing and could be as productive down the pub! So let’s first define our goal for working with BITS today.
So as it is slow internet day again here in the office, I have a file that I wish to transfer using bits from a server. As I would be grumpy if someone uses my bandwidth. I will host a file on my personal web space.
www.hazzy.co.uk\bits\PSIMAGE.JPG
Let’s start our BITS scripting in PowerShell by doing the good old fashion
get-command *BITS*
Oh, nice, there are a few commands right out of the tin. We can go out on a limb and think that we want to
start-bitstransfer
But as ever, grumpy admin would rather know the answer than guess, so let go for a
get-help start-bitstransfer
So as we can see there are lots of parameters that could be of use to use. The one’s that catch my eye the most are the -source and –destination. These look like the very things we need to transfer our file and achieve our goal – Now the earlier version of BITS only supported HTTP/HTTPS but now you can also use UNC network shares, which is great! Just to prove the fact, I will grab a file over UNC (Yes I know locally hosted but it proves the protocol provider works with BITS)
So we can do a command like this
Start-BitsTransfer -Source ‘\\127.0.0.1\c$\test\test.html’ -Destination ‘C:\Users\Hazzy\Desktop\log.txt
or we can do a command like this to prove it works with HTTP
Start-BitsTransfer -Source ‘http://www.hazzy.co.uk/bits/PSIMAGE.JPG’ -Destination ‘C:\Users\Hazzy\Desktop\PSIMAGE.JPG’
Now this a wonderful – but what the benefit of using this over curl – well when it such small files like this, well nothing tbh! The size of the file being so small. It seems a waste of CPU cycles to get this file via BITS. However, let do the same with a larger file. Now we don’t want to choke the network up when we are downloading this larger file (1Gig) file do we?
Bits is intelligent and download when the network isn’t busy, or you’re not busy etc, also it works on a job methodology. This means you create the job, the bits service processes that job, it provides an update . This means we can poll the status of the job, pass things like – cancel and suspend to the BITS service. As you can see, from the results of the Get-Help *BITS* these functions are exposed as cmdlets.
So in order to get the information from the transfer you can reference the job. As the image is so small it will be completed before we can ever poll the job for the transfer state. Lets work with a larger file.
http://www.hazzy.co.uk/bits/BITS.ZIP
This file is just over a gig in size, please don’t make me grumpy and use up all my server bandwidth…
Now that is all well and good but as you see, if we just execute the Start-BitsTransfer. We have to wait for the job to finish prior to getting the ,so what if we want to do it asynchronous, easy we saw a parameter for that didn’t we 🙂 –asynchronous. This is easy isn’t it! This adds great versatility.
This is great, but how then do we then get information the BITS Job that we created?
get-bitstransfer
As you can see, it listed as transferring in the JobState. Being PowerShell cmdlets they of course support the pipe line as well so we can have some fun and do something like this
get-bitstransfer |suspend-bitstransfer
Then when we want to resume the download we can do
resume-bitstransfer
Notice that it didn’t resume asynchronously!!! This might catch you out, so be aware of this behaviour.
Now I started this blog entry because our network is slow, when I do grumpy admin stuff, I do it in my Azure VM. This means, I don’t break anything on my production network and I don’t have to turn on my home lab! However, this means I have the fast(ish) download speeds of Azure 🙁 which can sometimes be insanely fast! I have a VM which I use for web browsing, that I RDP into when web speeds are slow IE and I don’t trust the network too much! So you will have to excuse me deleting and recreating the job for screenshots, if you notice inconsistencies with the images…
Now let’s start to get smart about this – for my example I want to use the -asynchronous – but I also want to provide some feed back of my own rather than their wonderful green text progress bar, it could be I have some logic that needs to be done may that doesn’t depend on the downloading of files. The usage cases are vast!
So first let’s put the start-bitstransfer code in to an object, this will make it more useful!
$tx=Start-BitsTransfer -Source ‘http://www.hazzy.co.uk/bits/PSIMAGE.JPG’ -Destination ‘C:\Users\Hazzy\Desktop\PSIMAGE.JPG’ -Asynchronous
Then we will do a get-member on the object and see what we can play with 🙂 if you were smart you would have seen some of them previously.
Let’s dump the object to screen and have a look at it and see what information we have
$tx |fl
Excellent, there is quite a bit of information that can be useful to us… let use the JobState property to our advantage, it there so let’s use it!
The job state will be one of the following values
Transferring
Connecting
Transferred
Error
Suspended
So this is perfect for a SWITCH command, so we can craft a little bit of code such as this
switch($tx.JobState)
{
“Transferring” {write-warning “Transferring”}
“Connecting” {write-warning “Connecting”}
“Transferred” {write-warning “Transferred”}
“Error” {write-warning “Error”}
“Suspended” {write-warning “Suspended”}
}
(I suspended the job at this stage as it would download faster than I can grab screenshots)
Now this is ok, but not much use at the moment, as it only give a moment in time of that JobState. So let’s put it in a loop and tidy up our text a bit… again excuse the write-host, it’s a demo!!!
So I will be encasing it in a WHILE loop, so if the Job state is either starting (“Connecting”) or is in progress (“Transferring”) then it is going to poll the JobState via our SWITCH loop.
while (($tx.JobState -eq “Transferring”) -or ($tx.JobState -eq “Connecting”))
{
switch($tx.JobState)
{
“Transferring” {write-host “Transferring still in progress $($tx.BytesTransferred/1MB) megs”}
“Connecting” {write-warning “Connecting to file server”}
“Transferred” {write-warning “The file has transferred fully”}
“Error” {write-warning “Error”}
“Suspended” {write-warning “The file transfer is Suspended”}
}
}
Also note that I am using the BytesTransferred property in the text!
If we execute a get-bitstransfer command now – you will see that the job is still there – we need to tidy up and clean up and complete the Job.
So we need to complete-bitstransfer in order to totally finish and move the file from the download cache to the final location.
So let’s do a
$tx | complete-bitstransfer
We could even put that in the script as the final line outside of the while loop.
“Transferred” {$tx | complete-bitstransfer}
There a many viable uses for this and BITS is a powerful fundamental, and you can create many BITS jobs. For example, my friend, yes grumpy does have them, stop laughing. Used BITS as a method of syncing his home media system between his two homes. This worked great, media just appeared every so often and didn’t adversely affect day today internet usage 🙂
So in summary, we had a very basic look at BITS, we seen how to create a BITS job, how to poll information from a job if you want to, and how to complete a job.
This can be a great tool in your admin pocket… Play experiment… perhaps you can ditch finally Robocopy.
Hazzy