2016-10-18

Turn on/off any PC with an ATX PSU and InfraRed remote

My HTPC has/had a CIR which allowed me to turn it on via my Harmony remote, but one day it stopped working and my attempts to fix it totally broke it.
So my 1st idea was I'll buy a new CIR device, but I couldn't find any.
My 2nd idea was get a new Motherboard, but that meant new CPU (Skylake i7-6700k) + RAM (DDR4) bcos there's no point getting a new Mobo if your not getting the latest and greatest, and I couldn't find any which turned on via IR.
My 3rd idea was build something :), this turned out to be ridiculously easy.

What would I need? Some way of automating pressing the button for 2 seconds, bcos that turns the PC on and off, and something to accept an IR signal.
I knew ATX PSU's have a 5v standby power supply, so IR relay would need to operate on 5v.

A quick google didn't help, so I went to Alibaba and found exactly what I was looking for, a 5v IR relay with timer function. I then went to eBay bcos I prefer the buying experience. Programmable Timer Relay Module + IR Remote Controller for $5 how awesome is that!?
3 weeks later it arrives and I proceed to install it. 


Please excuse the poor drawing, I don't have Visio installed on this PC.

Steps:
  1. Test relay to ensure it works.
  2. Program your universal IR remote unless you want to use the included one. My Harmony Elite had a really hard time learning the IR command, and even when it did it wouldn't work the 1st time, but it eventually learnt the command.
  3. Set relay time to 2 seconds, shorter will turn it on, but may not turn it off. 4 seconds will force a power cut.
  4. If required extend the infrared phototransistor, black shiny thing with 3 pins. I extended mine by 30cm to have it sit outside the case.
  5. Either find 5v on a motherboard pin header (there's bound to be a couple) or get it directly from the ATX connector.
  6. 5v in to the IR relay power input.
  7. Run 2 wires from relay output NO + COM to the Power Switch pins on your motherboard.
  8. T join the case front panel power switch to the Power Switch pins on your motherboard so you can still use the normal power switch.
  9. Test. Apart from the Harmony learning command issue, it has worked flawlessly for the past 2 weeks and I like that it turns off instead of the Alt+F4 I used to do. I even use an Amazon Echo + Harmony + Yonomi to voice control it with; Alexa, turn PC on/off.
Relay with extended phototransistor

T/Y join of front panel I/O + Relay NC/COM

The relay on top of the PSU in the case




2016-09-27

Microsoft SharePoint (Unreleased) for Android.

Some of us can't stand iOS but there's no denying it's the primary mobile platform and it has a SharePoint. Microsoft's just released an early access version of the Andoird app on the Play Store.
The SharePoint app includes all the things you'd expect to find - managing team sites, document storage, Office 365 integration, and collaboration features with other team members. Documents can be edited with the Office Mobile apps (Word, Excel, PowerPoint, and OneNote), making for easy updating on your Android phone or tablet. The app is powered by Microsoft Graph, which "makes it faster to get to content and people you work with".

 Microsoft SharePoint (Unreleased)- screenshot thumbnail   Microsoft SharePoint (Unreleased)- screenshot thumbnail   Microsoft SharePoint (Unreleased)- screenshot thumbnail   Microsoft SharePoint (Unreleased)- screenshot thumbnail   Microsoft SharePoint (Unreleased)- screenshot thumbnail   Microsoft SharePoint (Unreleased)- screenshot thumbnail

2016-06-30

PowerShell function to create Azure ARM VM with Public IP

This function is intended to reside within the logic of a larger script for deploying an entire resource group. The function should ideally be fed from a JSON or XML configuration file.
It takes a whole bunch of inputs relating to Azure VMs and provisions a VM within a resource group and VNet with a public IP. The Network Security Group settings need to be amended as required.
I've extracted some of the required variables, but these could also be passed as parameters.

[string]$resGroup = "IIOS" [string]$location = "australiaeast" [int]$script:ipStart = 4 [string]$saName = $($saName -creplace '[^a-zA-Z0-9]','').ToLower() [string]$vnName = $($resGroup +"-vNet1") function Create_VMRole([string]$vmName, [string]$vmSize, [string]$vmDesc, [int]$dataDiskSize, [string]$PublisherName, [string]$Offer, [string]$Skus) { while(($vmName.length -gt 15) -or !$vmName){ Write-Host "Virtual Machine Name '$vmName' is too long or empty" "Yellow" [string]$vmName = read-host "Please enter a valid Virtual Machine Name..." Write-Host "`nYou entered '$vmName'`n" "Yellow" } Write-Host "[CREATING] $vmDesc Virtual Machine '$vmName'" $vmAvailabilitySet = $($vmName +"AvailabilitySet") if(!($vmSet = Get-AzureRMAvailabilitySet -Name $vmAvailabilitySet -ResourceGroupName $resGroup)) { Write-Host "[CREATING] AvailabilitySet '$vmAvailabilitySet' for $vmDesc Virtual Machine '$vmName'" $vmSet = New-AzureRMAvailabilitySet -Name $vmAvailabilitySet -ResourceGroupName $resGroup -Location $location } $vnet = Get-AzureRMVirtualNetwork -Name $vnName -ResourceGroupName $resGroup Write-Host "[CREATING] PublicIpAddress for '$vmName'" $pip = New-AzureRMPublicIpAddress -Name $($vmName +"-PublicIP1") -ResourceGroupName $resGroup -Location $location -AllocationMethod Dynamic $nicIP = $("10.0.0." + $script:ipStart++) Write-Host "[CREATING] NetworkInterface with PrivateIP '$nicIP' for '$vmName'" $nic = New-AzureRMNetworkInterface -Name $($vmName +"-NIC1") -ResourceGroupName $resGroup -Location $location -SubnetId $vnet.Subnets[0].Id -PublicIpAddressId $pip.Id -PrivateIpAddress $nicIP $vm = New-AzureRMVMConfig -VMName $vmName -VMSize $vmSize -AvailabilitySetId $vmSet.Id $storageAcc = Get-AzureRMStorageAccount -ResourceGroupName $resGroup -Name $saName if($dataDiskSize -gt 0) { $vhdURI = $($storageAcc.PrimaryEndpoints.Blob.ToString() + "vhds/" + $vnName +"-"+ $vmName +"-Data1.vhd") Add-AzureRMVMDataDisk -VM $vm -Name "Data1" -DiskSizeInGB $dataDiskSize -VhdUri $vhdURI -CreateOption empty } $vm = Set-AzureRMVMOperatingSystem -VM $vm -Windows -ComputerName $vmName -Credential $vmCred -ProvisionVMAgent -EnableAutoUpdate #-TimeZone $TimeZone $vm = Set-AzureRMVMSourceImage -VM $vm -PublisherName $PublisherName -Offer $Offer -Skus $Skus -Version "latest" $vm = Add-AzureRMVMNetworkInterface -VM $vm -Id $nic.Id $osDiskUri = $($storageAcc.PrimaryEndpoints.Blob.ToString() + "vhds/" + $vnName +"-"+ $vmName +"-System.vhd") $vm = Set-AzureRMVMOSDisk -VM $vm -Name "System" -VhdUri $osDiskUri -CreateOption fromImage $newVM = New-AzureRMVM -ResourceGroupName $resGroup -Location $location -VM $vm return $newVM } Example usage: Create_VMRole "dbVM1" "Standard_D3_V2" "SQL Server Primary" 300 "MicrosoftSQLServer" "SQL2014SP1-WS2012R2" "Standard"

2016-01-10

PowerShell function to Get Term from SharePoint Term Store

Very useful if you're updating taxonomy fields.
Takes 3 inputs; the Site URL, the Taxonomy field object and the Term string.
The function gets a reference to the site's term store and then executes the GetTerm method, (more info here: TermSet.GetTerms) and finally return a Term object.


function GetTerm([string]$siteUrl, [Microsoft.SharePoint.Taxonomy.TaxonomyField]$oField, [string]$termStr) { if(!$oField.IsTermSetValid) { Write-Host "[ERROR] $($oField.Title) IsTermSetValid is FALSE" return $null; } $taxonomySession = Get-SPTaxonomySession -Site $siteUrl; if(($taxonomySession -eq $null) -or ($taxonomySession -eq $null)) { Write-Host "[ERROR] Taxonomy Session is null, Metadata Service App Proxy default storage location for column specific term sets is CHECKED and the user account has access" return $null } $oTermStore = $taxonomySession.DefaultSiteCollectionTermStore; if($oTermStore -eq $null) { $oTermStore = $taxonomySession.TermStores[0]; } if($oTermStore -eq $null) { Write-Host "[ERROR] Unable to get a valid Term Store.`nEnsure $(whoami) is a Term Store administrator.`nEnsure the Managed Metadata Service Proxy property 'This service application is the default storage location for column specific term sets.' is checked." Red exit } $oTermSet = $oTermStore.GetTermSet($oField.TermSetId); [System.Guid]$gTermId = $oField.AnchorId; [int]$LCID = 1033; if(($gTermId.ToString() -eq "00000000-0000-0000-0000-000000000000") -or ($gTermId -eq $null)) { $oTerm = $oTermSet.GetTerms($termStr, $LCID, $true)[0]; if($oTerm -eq $null) { Write-Host "[ERROR] Term value: $termStr not found in TermSet $($oTermSet.Name)" Red } } else { $oAnchorTerm = $oTermSet.GetTerm($gTermId); $oTerm = $oAnchorTerm.Terms[$termStr]; if($oTerm -eq $null) { Write-Host "[ERROR] Term value: $termStr not found in $($oTermSet.Name);$($oAnchorTerm.GetPath())" Red } } return $oTerm }
Below is an example of how to use the function and the returned Term object to set the default value for a field.

$oField = $oWeb.Fields.GetField("Document Type") $oTerm = GetTerm $oWeb.Site.Url $oField "Proposal" if($oTerm -ne $null) { $taxonomyValue = New-Object Microsoft.SharePoint.Taxonomy.TaxonomyFieldValue($oField); $taxonomyValue.TermGuid = $oTerm.Id.ToString(); $taxonomyValue.Label = $oTerm.Name; $oField.DefaultValue = $taxonomyValue.ValidatedString; $oField.PushChangesToLists = $true $oField.Update($true) Write-Host "Setting Default Value $($oField.TypeAsString):$($oField.Title) : '$($taxonomyValue.ValidatedString)'" Yellow }

2014-10-12

PowerShell function to Copy the properties of Document Set, including Welcome Page and Allowed Content Types

While ostensibly simple the process to copy allowed content types and welcome page properties took a while to figure out.
The function takes 2 input; the source Content Type (CT) for the Document Set (DS), and the target CT for the DS. It assumes both have been created and referenced.
It then gets a reference to the source DS Template, and loops through its properties to copy them to the target CT.
There are a couple of 2 second sleeps in there bcos in the environment where I was using it sometimes the re-referencing wouldn't work without them.


function Copy_DocSet_Properties([Microsoft.SharePoint.SPContentType]$oTargetDSCT, [Microsoft.SharePoint.SPContentType]$oSourceDSCT) { Write-Host "`t Setting '$($oTargetDSCT.Name)' Welcome page properties" if($oSourceDSCT -ne $null) { #https://msdn.microsoft.com/en-us/library/microsoft.office.documentmanagement.documentsets(v=office.14).aspx # AllowedContentTypes Property Microsoft.Office.DocumentManagement.DocumentSets.AllowedContentTypeCollection AllowedContentTypes {get;} # DefaultDocuments Property Microsoft.Office.DocumentManagement.DocumentSets.DefaultDocumentCollection DefaultDocuments {get;} # Equals Method bool Equals(System.Object obj) # GetHashCode Method int GetHashCode() # GetType Method type GetType() # SharedFields Property Microsoft.Office.DocumentManagement.DocumentSets.SharedFieldCollection SharedFields {get;} # ToString Method string ToString() # Update Method void Update(bool bPushDown) # WelcomePageFields Property Microsoft.Office.DocumentManagement.DocumentSets.WelcomePageFieldCollection WelcomePageFields {get;} # WelcomePageView Property Microsoft.SharePoint.SPView WelcomePageView {get;set;} $oSourceDSCTT = [Microsoft.Office.DocumentManagement.DocumentSets.DocumentSetTemplate]::GetDocumentSetTemplate($oSourceDSCT) $oTargetDSCT1 = $oTargetDSCT.ParentWeb.ContentTypes[$oTargetDSCT.Id] $oNewDST = [Microsoft.Office.DocumentManagement.DocumentSets.DocumentSetTemplate]::GetDocumentSetTemplate($oTargetDSCT1) $oNewDST.AllowedContentTypes.Clear() foreach($ctId in $oSourceDSCTT.AllowedContentTypes.GetEnumerator()) { $DSACT = $oTargetDSCT.ParentWeb.ContentTypes[$ctId] if(!$DSACT) { $DSACT = Create_CTFS $oTargetDSCT.ParentWeb $($oWebSource.ContentTypes[$ctId].Name) } if($DSACT) { $oNewDST.AllowedContentTypes.Add($DSACT.Id) Write-Host "`t Added Allowed Content Type '$($DSACT.Name)'" } else { Write-Host "[ERROR] Content Type '$($oWebSource.ContentTypes[$ctId].Name) ($ctId)' doesn't exist, so it can't be added to the Document Set" "red" } } $oNewDST.Update($false) sleep 2 $oTargetDSCT1 = $oTargetDSCT.ParentWeb.ContentTypes[$oTargetDSCT.Id] $oNewDST = [Microsoft.Office.DocumentManagement.DocumentSets.DocumentSetTemplate]::GetDocumentSetTemplate($oTargetDSCT1) foreach($oSFld in $oSourceDSCTT.WelcomePageFields.GetEnumerator()) { $oField = $oTargetDSCT1.Fields[$oSFld.Title] if($oField) { $oNewDST.WelcomePageFields.Add($oField) Write-Host "`t Added Welcome Page Field '$($oField.Title)'" } else { Write-Host "[ERROR] Unable to get reference to Source Field '$($oSFld.Title)' in content type $($oTargetDSCT1.Name)" } } $oNewDST.Update($false) sleep 2 $oTargetDSCT1.Update($false) $oTargetDSCT1 = $oTargetDSCT.ParentWeb.ContentTypes[$oTargetDSCT.Id] foreach($doc in $oSourceDSCT.XmlDocuments) { [xml]$xmldoc = $doc # "http://schemas.microsoft.com/office/documentsets/sharedfields" # "http://schemas.microsoft.com/office/documentsets/defaultdocuments" # "http://schemas.microsoft.com/office/documentsets/welcomepageview" # "http://schemas.microsoft.com/sharepoint/events" # "http://schemas.microsoft.com/office/documentsets/allowedcontenttypes" # "http://schemas.microsoft.com/office/documentsets/welcomepagefields" # "http://schemas.microsoft.com/sharepoint/v3/contenttype/forms" # "http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url" if(($xmldoc.FirstChild.Attributes[0].Value -notmatch "welcomepagefields") -and ($xmldoc.FirstChild.Attributes[0].Value -notmatch "events") -and ($xmldoc.FirstChild.Attributes[0].Value -notmatch "forms")) { Write-Host "`t Updating '$($xmldoc.FirstChild.Attributes[0].Value)'" try { $oTargetDSCT1.XmlDocuments.Delete($xmldoc.FirstChild.Attributes[0].Value) #$oTargetDSCT1.Update($false) $oTargetDSCT1.XmlDocuments.Add($doc) } catch { Write-Host "[ERROR] In Copy_DocSet_Properties '$($oTargetDSCT.Name)' unable to Set Welcome Page Properties" "red" Write-Host "[ERROR] $($_.Exception)" "red" Write-Host "[ERROR] $($_.ScriptStackTrace)" "red" } } } $oTargetDSCT1.Update($false) } }

2014-09-12

Generic PowerShell Function to Create a Document Set SharePoint 2013 On-Prem

The function accepts 4 paramters the Site Url, the Library name where the Document Set will be created, the Content Type of the Document Set and finally the Name of the Document Set.
To set properties for the Document Set, and simple modification would be to include a key pair Hash table, the function declares an empty one ($dsProps) 

Example would be:
[hashtable] $dsProps = @{"Key" = "Value";"Key" = "Value";}

or
$dsProps["Key"]="Value" 
$dsProps["Key"]="Value"

The function:
function createDocumentSets([string]$SiteUrl, [string]$LibraryName, [string]$CTName, [string]$dsName) { [Microsoft.SharePoint.SPWeb]$oWeb = Get-SPWeb $SiteUrl [Microsoft.SharePoint.SPList]$oLibrary = $oWeb.Lists[$LibraryName] if($oLibrary.Title -eq $LibraryName) { [Microsoft.SharePoint.SPContentType]$oCT = $oLibrary.ContentTypes[$CTName] if($oCT.Name -eq $CTName) { [Hashtable]$dsProps = @{} [Microsoft.Office.DocumentManagement.DocumentSets.DocumentSet]$newDs =
[Microsoft.Office.DocumentManagement.DocumentSets.DocumentSet]::Create($oLibrary.RootFolder,
$dsName,$oCT.ID,$dsProps,$true)
Write-Host "`tCreating '$dsName' ($CTName) in Library '$LibraryName' @ '$SiteUrl'" } else { Write-Host "[ERROR] Getting Content Type '$CTName' on Library '$LibraryName' @ '$SiteUrl'" } } else { Write-Host "[ERROR] Getting Library '$LibraryName' @ '$SiteUrl'" } $oWeb.Dispose() }