I had a scenario when my git gui wouldn’t delete a remote branch – and neither would the usual command that I use.
In the end, this sorted it for me:
|
1 |
git push origin --delete branchname |
I had a scenario when my git gui wouldn’t delete a remote branch – and neither would the usual command that I use.
In the end, this sorted it for me:
|
1 |
git push origin --delete branchname |
A time to reflect and resolve to do things differently. This years list:
Stop shouting: I’m sometimes guilty of raising my voice at the kids when they aren’t behaving but it’s not exactly a role model I want to set. Do I really expect them to be quiet when I’m loud?!
Declutter: I have too much stuff. I’m going to try and get rid of at least one thing a day (bin, recycle, upcycle, sell, giveaway).
Socialise more: In 2016 I found it difficult to socialise because I was too tired … now the kids are a year older it should be easier due to improved sleeping (fingers crossed).
Blog more: I didn’t write much in 2016 but I did re-read previous posts for useful snippets. Seems to make sense to write more.
Lunchtime walk: Before moving South I used to have a walk every lunch time. It seems a good habit for 2 reasons; The only other exercise I get is playing with the kids or working in the garden; Taking a break to clear my mind and come back fresh.
Progress will be posted on my blog – because I’ll be doing more of that 😉
I was working with on a .net service that I wanted to run on my raspberry pi. Initially this was fairly easy but then I wanted to run it on startup as a service.
After a bit of digging I found out about mono-service and mono-service2 (for .net 1 and .net 2 respectively)
Working with this is as simply as …
To start a service
|
1 |
mono-service2 something.exe |
To stop a service
|
1 |
kill `cat /tmp/something.exe.lock` |
Woah – ok stopping isn’t so straightforward …
Basically when the service starts it puts a lock file in the /tmp folder. This is just a text file that contains the process id (pid) of the exe that is running. By doing the cat, and passing that to kill, the service will stop.
Next up was to get it to run on start up.
I found a useful bash script to start, stop and restart the service … http://www.geekytidbits.com/start-stop-daemon-with-mono-service2/
Unfortunately this didn’t work immediately for me as my version of linux was built differently and didn’t have some of the parts this script depended on.
My finished script now looks like this:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
#!/bin/sh daemon_name=BPI PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/bin/mono/mono-service2 NAME=BPI DESC=BPI . /lib/lsb/init-functions MONOSERVER=$(which mono-service2) MONOSERVER_PID=$(cat /tmp/BPI.lock) case "$1" in start) log_daemon_msg "Starting BPI" if [ -z "${MONOSERVER_PID}" ]; then ${MONOSERVER} -l:/tmp/BPI.lock -d:/home/pi/bpi/current/ /home/pi/bpi/current/bpi.daemon.exe log_end_msg 0 else -l log_failure_msg "BPI is already running!" exit 1 fi ;; stop) log_daemon_msg "Stopping BPI" if [ -n "${MONOSERVER_PID}" ]; then kill ${MONOSERVER_PID} rm /tmp/BPI.lock log_end_msg 0 else log_failure_msg "BPI is not running" exit 1 fi ;; restart) $0 stop sleep 1 $0 start log_end_msg 0 ;; *) log_action_msg "usage: $0 {start|stop|restart}" esac exit 0 log_end_msg 0 |
This was put in \etc\init.d\bpi.sh and I did a chmod to make it match the others in that directory.
Note that there are a couple more parameters to our start command … -l to tell it where to put the lock file and -d to give it a start directory (my application writes logs and they would appear in funny places without this).
Finally the following command sets things up to start and stop in different runlevels:
sudo update-rc.d bpi.sh defaults
I’ve had this script for many years but currently I don’t have a use for it so I’m getting rid of it but putting it here for future reference in case I need it again.
It’s got code to retrieve data from a database and convert it to a tab delimited string. There’s more code which then parses this into tasks. The upshot of this is that I’ve used it in the past to take data from the clipboard (having come from excel).
The code has been anonymised which will have introduced a bug or two but the gist of it is valid.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
Dim sqlUserList As String Dim strConn As String Dim strOutlookFolder As String Dim strExternalOwner As String 'Entry point for macro Sub UpdateData() 'set global variables here sqlUserList = "'mrBob', 'mrBill', 'mrTed'" strConn = "Provider=SQLOLEDB;Data Source=myserver;Initial Catalog=mydatabase;User ID=myuser;Password=mypass;" strOutlookFolder = "Mailbox - My, Name\Folder Name" strExternalOwner = "TheOwner" Dim strClip As String Dim Lines() As String strClip = GetDataFromExternal() Lines = Split(strClip, vbCrLf) CreateTasks Lines CompleteTasks Lines End Sub Function GetDataFromExternal() 'Define SQL strSQL = "SELECT data_1, data_2, data_3 From MyTable WHERE Owner IN (" & sqlUserList & ") ORDER BY data_1, data_2" 'Declare variables' Dim objMyConn As ADODB.Connection Dim objMyRecordset As ADODB.Recordset Set objMyConn = New ADODB.Connection Set objMyRecordset = New ADODB.Recordset 'Open Connection' objMyConn.ConnectionString = strConn objMyConn.Open 'Open Recordset' objMyRecordset.Open strSQL, objMyConn 'Gather data strOutput = "" Do Until objMyRecordset.EOF For I = 0 To objMyRecordset.Fields.Count - 1 If I > 0 Then strOutput = strOutput + vbTab End If strOutput = strOutput + Replace(Replace(CStr(objMyRecordset.Fields(I)), vbCrLf, ""), vbTab, "") Next strOutput = strOutput + vbCrLf objMyRecordset.MoveNext Loop 'Clean up objMyRecordset.Close objMyConn.Close Set objMyConn = Nothing Set objMyRecordset = Nothing 'Return data GetDataFromExternal = strOutput End Function Sub CreateTasks(SRLines() As String) Dim sr As String Dim SRCells() As String Dim objTask As Outlook.TaskItem Dim targetDate As Date Dim targetY As Integer Dim targetM As Integer Dim targetD As Integer For I = 0 To UBound(SRLines) - 1 SRCells = Split(SRLines(I), vbTab) 'search for existing task Set objTask = FindTask(SRCells(2), SRCells(0) & " - " & SRCells(5)) If (objTask Is Nothing) Then 'not found - raise it as new If (SRCells(8) <> "01/01/1753") Then targetY = Mid(SRCells(8), 7, 4) targetM = Mid(SRCells(8), 4, 2) targetD = Mid(SRCells(8), 1, 2) targetDate = DateSerial(targetY, targetM, targetD) Else targetDate = DateSerial(0, 0, 0) End If CreateTask SRCells(2), SRCells(0) & " - " & SRCells(5), SRCells(4) & vbCrLf & SRCells(7) & vbCrLf & SRCells(6), targetDate End If Next End Sub Sub CreateTask(strOwner As String, strSubject As String, strDescription As String, dtDue As Date) Dim olTask As Outlook.TaskItem Dim olApp As Outlook.Application Dim folder As MAPIFolder 'create task in custom named task folder Set folder = GetFolder(strOutlookFolder) Set olTask = folder.Items.Add(olTaskItem) 'using a custom property to track who the task is assigned to Set objProperty = olTask.UserProperties.Add(strExternalOwner, olText) If TypeName(objProperty) <> "Nothing" Then Select Case strOwner Case "MrBob" objProperty.Value = "Bob" Case "MrBill" objProperty.Value = "Bill" Case "MrTed" objProperty.Value = "Ted" Case Default objProperty.Value = strOwner End Select End If olTask.Body = strDescription olTask.Subject = strSubject olTask.Categories = "MyCategory" If (dtDue <> DateSerial(0, 0, 0)) Then olTask.DueDate = dtDue End If olTask.Save End Sub Sub CompleteTasks(SRLines() As String) Dim objFolder As Outlook.MAPIFolder Set objFolder = GetFolder(strOutlookFolder) CompleteFolderTasks SRLines, objFolder End Sub Sub CompleteFolderTasks(SRLines() As String, objFolder As Outlook.MAPIFolder) Dim objTasks As Outlook.Items Dim objTask As Outlook.TaskItem Dim objCategory As Outlook.Category Dim SRCells() As String Dim taskIsValid As Boolean Set objTasks = objFolder.Items For Each objTask In objTasks 'first filter for INC If Left(objTask.Subject, 3) = "INC" Then 'then double check category If (InStr(objTask.Categories, "Category") > 0) Then 'now we have one we need to check if it's in the list of SRLines taskIsValid = False For I = 0 To UBound(SRLines) - 1 SRCells = Split(SRLines(I), vbTab) If (objTask.Subject = SRCells(0) & " - " & SRCells(5)) Then taskIsValid = True Exit For End If Next 'found a missing one If (taskIsValid = False) Then objTask.Categories = "Category Complete" objTask.Save End If End If End If Next End Sub 'Utility functions Function FindTask(strOwner As String, strSubject As String) Dim objFolder As Outlook.MAPIFolder Dim objTasks As Outlook.Items Dim objTask As Outlook.TaskItem Dim strFind As String Set objFolder = GetFolder(strOutlookFolder) Set objTasks = objFolder.Items 'escape special characters strSubject = Replace(strSubject, "'", "''") strSubject = Replace(strSubject, """", """""") strFind = "[Subject] = '" & strSubject & "'" Set objTask = objTasks.Find(strFind) Set FindTask = objTask End Function Public Function GetFolder(strFolderPath As String) As MAPIFolder ' strFolderPath needs to be something like ' "Public Folders\All Public Folders\Company\Sales" or ' "Personal Folders\Inbox\My Folder" Dim objApp As Outlook.Application Dim objNS As Outlook.NameSpace Dim colFolders As Outlook.Folders Dim objFolder As Outlook.MAPIFolder Dim arrFolders() As String Dim I As Long On Error Resume Next strFolderPath = Replace(strFolderPath, "/", "\") arrFolders() = Split(strFolderPath, "\") Set objApp = Application Set objNS = objApp.GetNamespace("MAPI") Set objFolder = objNS.Folders.Item(arrFolders(0)) If Not objFolder Is Nothing Then For I = 1 To UBound(arrFolders) Set colFolders = objFolder.Folders Set objFolder = Nothing Set objFolder = colFolders.Item(arrFolders(I)) If objFolder Is Nothing Then Exit For End If Next End If Set GetFolder = objFolder Set colFolders = Nothing Set objNS = Nothing Set objApp = Nothing End Function |
Just making a quick reference for myself of the info found on msdn.
Take a look at the following registry keys
Frameworks 1 – 4
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP
Frameworks >= 4.5
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\Release
where
378389 = .NET Framework 4.5
378675 = .NET Framework 4.5.1 installed with Windows 8.1
378758 = .NET Framework 4.5.1 installed on Windows 8, Windows 7 SP1, or Windows Vista SP2
379893 = .NET Framework 4.5.2
As an admin of a TFS server I wanted to be able to send an email to people reminding them of any pending changes they may have.
I knocked up a quick application and have now configured it to run once a week with a scheduled task.
The main logic to get pending change sets is (where _vcs is a VersionControlServer from the Microsoft.TeamFoundation.VersionControl.Client namespace):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var itemSpecs = new[] { new ItemSpec("$/", RecursionType.Full) }; var pendingSets = _vcs.QueryPendingSets(itemSpecs, null, null); var pendingChanges = (from pendingSet in pendingSets from pendingChange in pendingSet.PendingChanges orderby pendingSet.OwnerDisplayName, pendingChange.ServerItem select new PendingChange { OwnerDisplayName = pendingSet.OwnerDisplayName, OwnerName = pendingSet.OwnerName, LocalItem = pendingChange.LocalItem, ServerItem = pendingChange.ServerItem, PendingSetName = pendingChange.PendingSetName + " [" + pendingSet.Computer + "]" }).ToList(); |
The PendingChange class is a simple POCO:
|
1 2 3 4 5 6 7 8 |
public class PendingChange { public string OwnerDisplayName { get; set; } public string OwnerName { get; set; } public string LocalItem { get; set; } public string ServerItem { get; set; } public string PendingSetName { get; set; } } |
After that it was a simple case of looping through the PendingChanges List<> building up emails and sending them.
As I keep having to figure this out every time I come to do it I’m leaving it here for reference.
To find a SharePoint feature when you only know part of the name of it the following command can be used:
|
1 |
Get-SPFeature | where { $_.DisplayName -like "*something*" } | format-list -property displayname |
I’m beginning to hear a lot more about VPN’s (personal use for anonymity) in the press and I’m a bit worried it’s not understood enough.
Sales pitch: Get a VPN and your internet anonymity is restored.
Truth: It can be, but you have to be careful.
Other people will know more than me – there more than likely will be more to worry about than this. My main concern: cookies.
You get a lovely new vpn and then you use the same browser and user account to get on the net. BAM! You’re not anonymous any more!
A lot of the VPN providers sell the fact that it’s good for internet cafes. This is partly true – it will stop the others on the same wifi from snooping. The problem is that as soon as you log on to Facebook via your VPN you’re not anonymous. These are two different uses for a VPN and they’re not compatible. If you’re looking for anonymity what are you doing on a social network?! Scared of your ISP? You should be just as scared of any website you need to log on to!
My steps for a nice clean VPN:
All for now …
I needed to set up a new web application that was a copy of an existing web application. The constraint was that there was only one farm available to work with (I did have other farms but they were running different versions of SQL server).
Approach 1
I’ll first point out that this didn’t work, skip ahead if you’re not interested.
I went through the following steps:
The result was the database attached but it had no site collections in it.
It turns out that this approach could work but only if you attach it to a different farm. You can then backup that database and restore/attach it back on the source farm.
As I stated at the beginning – I didn’t have the luxury of a second farm.
Approach 2
The only option left that I could think of was to backup and restore each site collection manually.
I knocked up the following powershell script to automate this and it worked …
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$sourceApp = "http://source.example.com" $targetApp = "http://target.example.com" $app = Get-SPWebApplication -Identity $sourceApp foreach ($site in $app.Sites) { Write-Host performing backup of $site.URL Backup-SPSite -Identity $site.URL -Path "c:\backup\migration.bak" -force $newurl = $site.URL -replace $sourceApp, $targetApp Write-Host restoring into $newurl Restore-SPSite -Identity $newurl -Path "c:\backup\migration.bak" -force -confirm:$false } |
I needed an easy way to create users in Active Directory.
PowerShell to the rescue … although it didn’t work out.
The PowerShell command New-ADUser depends on AD having web services enabled which is a feature that came out with 2008 R2 – needless to say the AD server I was working with didn’t have this. So I fell back to the good old fashioned command line: dsadd user.
I put together an excel with columns like this:
|
1 2 3 4 5 6 7 |
A - Company Name B - User Prefix C - First Name D - Last Name E - Email Address F - Password G - a formula to generate the command using data in the row ... |
|
1 |
=CONCATENATE("dsadd user ""CN=", C2, " ", D2, ",OU=users,OU=my,DC=dc,DC=path"" -samid """, B2, "-", D2, """ -upn """, B2, "-", D2, "@dc.path"" -pwd """, F2, """ -fn """, C2, """ -ln """, D2, """ -email """, E2, """ -desc """, A2, " - User"" -d ""dc.path"" -display """, C2, " ", D2, """") |
So for this data
|
1 2 3 4 5 6 |
A - acme corp B - acme C - John D - Smith E - John.Smith@AcmeCorp.com F - Password1 |
The following command is generated:
|
1 |
dsadd user "CN=John Smith,OU=users,OU=my,DC=dc,DC=path" -samid "acme-Smith" -upn "acme-Smith@dc.path" -pwd "Password1" -fn "John" -ln "Smith" -email "John.Smith@AcmeCorpm.com" -desc "acme corp - User" -d "dc.path" -display "John Smith" |
This is going to save me minutes – literally minutes – every month!