ADFS SQL Migration

You may want to move your back end ADFS dababases to a new SQL server. This guide shows you how.

This guide is intended for ADFS clusters where you have more than one ADFS server using MS SQL. There are other ways of setting up ADFS with WID (SQL Express). This guide is only for a shared MS SQL server.

Prep work:

  • Ensure you have your new ADFS SQL databases in place on the new SQL server. Just make a copy only backup and restore over the top of new blank databases on the new SQL server.
  • Ensure you have permissions setup in SQL for the new databases. Use the same permissions that were setup before.
  • IMPORTANT: Use the below commands to see what settings are currently in the ADFS servers.

$adfsSecurityTokenService = Get-WmiObject -namespace root/ADFS -class SecurityTokenService

Example Output: Data Source=<sqlservername>;Initial Catalog=AdfsConfigurationV3;Integrated Security=True;Min Pool Size=20

get-AdfsProperties | select artifactdbconnection

Example Output: Data Source=<sqlservername>;Initial Catalog=AdfsArtifactStore;Integrated Security=True;Min Pool Size=20


The trick here is that you need to run both command but the get/set-adfsproperties command only works when ADFS is running. The first WMI command will only work when ADFS is stopped. If you stop ADFS, run the first WMI command, and try to start ADFS it may fail to start. Then you can’t run the second command. So the order of these commands is very important.

How to switch it:

  1. Run the below commands while everything is running.
  2. The temp put one will fail. Ignore this.
  3. The set-adfsprops command should work (it won’t if adfs is off)
  4. Stop adfs services
  5. Run temp put again (should work now)
  6. Rename DBs on old server (to ensure you are no longer using them)
  7. Start services.
  8. Do this on both ADFS servers.

$adfsSecurityTokenService = Get-WmiObject -namespace root/ADFS -class SecurityTokenService
$adfsSecurityTokenService.ConfigurationdatabaseConnectionstring=”Data Source=<sqlservername>;Initial Catalog=AdfsConfigurationV3;Integrated Security=True;Min Pool Size=20″

Set-AdfsProperties –artifactdbconnection “Data Source=<sqlservername>;Initial Catalog=AdfsArtifactStore;Integrated Security=True;Min Pool Size=20”




Posted in Uncategorized | Leave a comment

PowerShell Certificate Request from Enterprise PKI CA Server

This command will allow you to quickly get a certificate automatically. This is very useful for automating deployments of IIS or other web services that require a certificate to function. It uses your windows EPKI servers to get the certificates. There are a few requirements though.


  1. You have access to the certificate templates
  2. You have your template setup to auto approve
  3. You have your template setup based on the web server template

Here is the set of commands. You move powershell to the local machine cert store (where IIS can get them and the type of template you are using would be stored). You then request the cert by template name. You can specify the subject name and other DNS names (note you can do a SANs cert here too). Once you have the cert the next command will set a friendly name for the cert (on this computer). The friendly name can be anything and will not transfer from computer to computer. It then outputs the thumbprint too.

Set-Location 'Cert:\LocalMachine\My'
$cert = Get-Certificate -Template "[cert_template_name_here]" -Url ldap: -SubjectName ("CN=" + "") -DnsName "", "blah", "", "tom", "" -CertStoreLocation Cert:\LocalMachine\My
gci | where {$_.Thumbprint -eq $cert.Certificate.Thumbprint} | foreach { $_.FriendlyName = "my blah and tom cert" }
Posted in IT | Tagged , | Leave a comment

ADFS Important URLs

After setting up ADFS I frequently forget the URLs used by ADFS. It’s funny that they don’t really show you these after an install. But here they are and what they are used for.


This is the IDP initiatedsign on page. This is where you can access your relying party trusts. This is used when the relying part does not support SP. (You need to use your ADFS server website to login to their services)



This is your ADFs federated metadata. This data can be published to the internet so that your relying party trusts can read what properties you send over in claims and what you accept. It also publishes your public certificate data so when your ADFS server auto renews certificates other servers can read this data automatically and update their end too. This avoids issues with the cert renewal process (if they support it).



This URL can be used by internal users via the IDP page to log directly into another relying party trust. This way the don’t have to actually use the IDP page manually. You just enter the partner URL found in the ADFS console for your relying party trust.


Posted in IT, Uncategorized | Tagged | Leave a comment

Server 2016 and Windows Updates

You may need to force Windows Server 2016 to rescan for windows updates. It has changed slightly in Server 2016. So here is how:

$list1 = (Get-ADComputer -Filter {OperatingSystem -Like "*server 2016*"} -properties operatingsystem).Name | where {$_ -match "PROD"} 
$list1 | foreach {
PsExec.exe -s -d "\\$($_)" c:\windows\system32\UsoClient.exe startscan
PsExec.exe -s -d "\\$($_)" wuauclt /reportnow
Posted in IT, Uncategorized | Tagged | Leave a comment

New new disk drives to Windows VMs in VMWare

You may want to add a bunch of new drives to your servers all at once. In my case this was useful for installing a new agent on a large amount of servers. These commands can be used with PowerCLI and WinRM to add new disk drives to the VMs, format them, and mount them as a drive letter in Windows. Then you are all set to use them right away.

Power CLI Commands:

#gather list

#static way
$VMsList = "VM1","VM2"

#dynamic way
$VMsList = (Get-VM | where {$_.Name -match "WIN"}).Name

#add the new disk as 10GB, persistent, and EagerZeroedThick
$VMsList | foreach {
	Get-VM "$($_)" | New-HardDisk -CapacityGB 10 -Persistence persistent -StorageFormat EagerZeroedThick


Next up you must connect to each Windows VM via PowerShell WinRM and format and mount the drives. This will move the CD ROM drive to F: from D:, initialize all disks as GPT, and then partition them as the D: drive letter.

$VMsList | foreach {
	Invoke-Command -ComputerName "$($_)" {
		#move cdrom drive to F: drive from D: drive
		Get-WmiObject -Class Win32_volume -Filter "DriveLetter = 'd:'" |Set-WmiInstance -Arguments @{DriveLetter='F:'}

		#format all new disks
		Get-Disk | Where partitionstyle -eq 'raw' | Initialize-Disk -PartitionStyle GPT -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -FileSystem NTFS -NewFileSystemLabel "" -Confirm:$false

		#setup new Disks, labels, and drive letters
		Get-Disk | foreach {
			if (($_.Size -eq 10GB)) {
				Set-Partition -DriveLetter (($_ | Get-Partition).DriveLetter)[1] -NewDriveLetter "D"


Posted in IT, Uncategorized | Tagged , , | Leave a comment

Exchange CAL Licensing – Mobile Device Policy

You may be forced to use an Exchange Enterprise CAL if you customize an Active Sync / Mobile Device policy. These commands help you find how Exchange thinks you are licensed and how you can fix it.


# Collect license info

$a1 = Get-ExchangeServerAccessLicenseUser -LicenseName "Exchange Server 2013 Standard CAL"

$a2 = Get-ExchangeServerAccessLicenseUser -LicenseName "Exchange Server 2013 Enterprise CAL"

#total standard licenses (even enterprise counts here)

#total enterprise licenses 

#total standard only licenses
$a1.count - $a2.count


Now take a look at what your mobile device polcy(ies) look like settings wise.

Get-MobileDeviceMailboxPolicy | select AllowBluetooth,AllowBrowser,AllowCamera,AllowConsumerEmail,AllowDesktopSync,AllowInternetSharing,AllowIrDA,AllowRemoteDesktop,AllowStorageCard,AllowTextMessaging,AllowUnsignedApplications,AllowUnsignedInstallationPackages,AllowWiFi,ApprovedApplicationList,UnapprovedInROMApplicationList


Set those settings back to the defaults (allowed) and it’ll take care of your licensing issues. But be warned that it could cause warnings or issues on any Active Sync users. You should test this with a new policy first before just changing the policy everyone is using.


Posted in IT, Uncategorized | Tagged , | Leave a comment

Checklist to review when inheriting an Exchange Server

These are all the settings that you should look into when working with a new Exchange server that you are not familiar with. There seem to be a ton of settings that are left forgotten over time and may need to be updated as the business changes over time.

  1. Organization configuration
    1. Get-OrganizationConfig
  2. Organization Transport (sending/receiving message limits)
    1. Get-TransportConfig | Format-List MaxReceiveSize,MaxSendSize,MaxRecipientEnvelopeLimit
  3. Active Sync Organization Configruation
    1. Get-ActiveSyncOrganizationSettings | FL DefaultAccessLevel,AdminMailRecipients
  4. Exchange Servers
    1. Get-ExchangeServer
  5. Mailbox Databases
    1. If in DAG or not
      1. Get-MailboxDatabaseCopyStatus
    2. Size restrictions
      1. Get-mailboxDatabase | select Identity,ProhibitSendReceiveQuota,ProhibitSendQuota,IssueWarningQuota,RecoverableItemsQuota,DeletedItemRetention
  6. Mailboxes
    1. Individual size restrictions
      1. get-mailbox | where { ($_.ProhibitSendQuota -ne “Unlimited”) -or ($_.ProhibitSendReceiveQuota -ne “Unlimited”) -or ($_.RecipientLimits -ne “Unlimited”) -or ($_.MaxSendSize -ne “Unlimited”) -or ($_.MaxReceiveSize -ne “Unlimited”) } | select ProhibitSendQuota, ProhibitSendReceiveQuota, RecipientLimits, MaxSendSize, MaxReceiveSize
    2. Full access
      1. get-mailbox | Get-MailboxPermission | where { ($_.AccessRights -eq “FullAccess”) -and ($_.IsInherited -eq $false)}
  7. Exchange Apps
    1. Get-app
  8. Malware Filter
    1. get-malwarefilterpolicy | select Name, Action, IsDefault, *Notifications, *SenderAdminAddress
  9. Outlook Anywhere
    1. Get-OutlookAnywhere | select ExternalHostname, InternalHostname, ExternalClientAuthenticationMethod, InternalClientAuthenticationMethod, IISAuthenticationMethods
  10. Malware Scans (Exchange A/V)
    1. Get-MalwareFilterPolicy
    2. Get-MalwareFilteringServer | fl *
  11. Transport Rules
    1. Get-TransportRule
  12. Receive Connectors
    1. Get-ReceiveConnector | select Name, Enabled, Bindings, AuthMechanism, RequireTLS, MaxMessageSize, MessageRateLimit, MaxRecipientsPerMessage, RemoteIPRanges
  13. Send Connectors
    1. Get-sendConnector | select Name, Enabled, RequireTLS, MaxMessageSize, AddressSpaces
  14. Outlook Web App Policies
    1. Get-OwaMailboxPolicy
  15. Public Folders
    1. Get-PublicFolder
Posted in IT | Tagged , | Leave a comment

Home Built Uninterruptible Power Supply (UPS)

A UPS can be a valuable tool to protect your electronics against power surges, brown outs, and black outs. I’ve always tried to use and maintain one at home for my own equipment. But they can be expensive and the batteries don’t seem to last long (duration of charge and overall lifetime). So I decided to build one of my own.

WARNING: I did some research online and it seemed pretty simple to build one. I’m by no means an expert in electronics so use this information at your own risk. There is danger in working with these types of electronics. You can potential start a fire or short out your equipment if you wire things improperly.

A few tips before we start:

  1. If you don’t understand completely what you are doing please stop
  2. DC wiring must never be reversed (positive to negative). This will usually destroy electronics. AC is different as it alternates in voltage both ways.
  3. Be sure your equipment is off when working on it. Use a multi meter to test it. Be sure to be set to AC or DC.
  4. Be very sure to use the correct gauge wiring when connecting components. Wires that can’t handle a high load will short out and burn up. This can cause a fire.
    1. Use online resources like wire guides to figure out what gauge you need
    2. The length of the wire is very important too. Short and direct runs are best.
  5. Don’t trust all information you see online. Including what you are reading now. This is a learning experience for me and I’ll be upgrading my UPS as I find flaws.

I decided on a pure sine wave inverted as I had issues with one that wasn’t a pure wave, it was a simulated sine wave. The difference is that some electronics don’t handle how quickly and sharply the voltages go up and down on the AC side. I had purchased a 2000 watt inverter and had issues powering up an old computer. It also had trouble with a electric fan. The fan is a great example showing how AC motors need the smooth sine wave increase and decrease in voltage to start and stop. (Think of moving a car with block wheels versus round wheels)

Parts List:

Wiring Diagram:

This system is pretty easy to build. You use the power inverter to power all of your AC equipment. The Iota 55 amp charger will charge the battery and power the inverter as long as it has power from the power grid. The battery is big enough to output enough amperage for the inverter (1,000 watts / 12 volts = 83 amps). The iota charger can’t supply enough power to the inverter if we have the maximum load on the inverter but this was OK with me as my power load is pretty small.


I’m using about 110 watts powering a few HP switches, cable modem, 2 PoE access points, a 4 disk enclosure, a Intel NUC, as well as a raspberry pi. I’m able to measure this with my bayite display. Then I was able to measure the load from my iota charger with a kill-a-watt AC power measuring device. The kill-a-watt came out to about 150 watts. So I’m seeing some loss in the conversion of AC to DC and this is normal. I’m sure there is even more loss from AC to DC and back to AC through the inverter. But this is the cost of a system like this.


Knowing my usage I estimated I would get about 8 hours of run time. A 100 amp/hour battery can output 100 amps (at 12 volts) for 1 hour or 10 amps for 10 hours. Since I’m using about 8 amps and you don’t want to discharge too low, i’d estimate 8 hours.


I did purchase a deep cycle battery. The difference between a regular sealed lead-acid battery and a deep cycle sealed lead-acid battery is the deep cycle will allow for a larger discharge and go down to a lower voltage without ruining the battery. If I remember correctly you don’t want to go below 10.8 volts charge on a lead-acid battery otherwise you will damage it. Speaking of this the iota charger had a separate accessory that can help keep batteries maintained properly. I had purchase this and installed it to help maintain my battery.


As for expansion I can add another battery to my setup to double my run time. You would want to connect it in parallel, not a series. In parallel the voltage stays the same and in a series it would double (this could cause damage to the inverter if it can’t accept much over 12 volts).


The gauge of the wire i used was very important. The lower the number the more amperage it will support but keep in mind the length is very important too. Too long and you can cause the same issue as having to thin of a wire. I tried to keep everything under 3 feet.



Posted in IT, Recent Projects | Leave a comment

Hyper-V Replication via PowerShell

I wanted to replicate a few VMs from one computer to another. These are just Windows 10 pro VMs running Hyper-V. I know most people would just use the Windows Server Hyper-V built-in replication functionality but I’m not running that OS. So here is the poor-man’s way of replicating the VMs and setting up automatic startup with PowerShell. Keep in mind that these Hyper-V hosts are both in the domain for this to work properly (this is mostly just for the SMB/CIFS file transfer).

The code below just needs paths and hostnames filled in. You’ll need to create a shared folder on the destination host as well. Then you can run this script as a scheduled task on both hosts. It needs more work but should cover basic functionality.

#holds primary copies, controls what script does on each computer
$hv_primary = "primary_hostname"

#filter out VMs by notes field
$critical_tag = "CRITICAL_VM"

switch ($env:computername) {
	"primary_hostname" { $hv_partner = "secondary_hostname" }
	"secondary_hostname" { $hv_partner = "primary_hostname" }
	default { exit }

if ($env:computername -eq $hv_primary) { 
	#run primary server functions
	if ((Test-NetConnection -ComputerName $hv_partner).PingSucceeded -eq $true) {
		write-host "partner $hv_partner is online. copy vm files to him."
		Get-VM | where {$_.Notes -match $critical_tag } | foreach {
			if (test-path ("\\$hv_partner\Hyper-V\" + $_.Name)) {
				write-host ("need to remove old copy first. path: " + ("\\$hv_partner\Hyper-V\" + $_.Name))
				remove-item -force -recurse ("\\$hv_partner\Hyper-V\" + $_.Name)
			} else {
				write-host ("exporting it now. path: " + "\\$hv_partner\Hyper-V\" + $_.Name)
				Export-VM -VM (get-vm $_.Name) -Path "\\$hv_partner\Hyper-V\"

} else {
	#run backup server functions (ensure we have VMs that are recent, test if primary online and boot if primary off.

	#ensure partner is online
	if ((Test-NetConnection -ComputerName $hv_partner).PingSucceeded -eq $true) {
		write-host "partner $hv_partner is online. no need to fire up VM's on this end."
		write-host "ensure our VM's are off. stop them now if running."
		Get-VM | where {$_.Notes -match $critical_tag } | where {$_.State -eq "Running"} | stop-vm
	} else {
		write-host "partner $hv_partner is NOT online."
		write-host "checking if VMs imported yet or not."
		$vm_list = (GCI "\\$env:computername\Hyper-V\" | ?{ $_.PSIsContainer })
		$vm_list | foreach {
			$this_vm_dir = $_

			write-host "check if this VM $($this_vm_dir.Name) is already imported"
			$this_vm = Get-VM ($this_vm_dir.Name)
			if ($this_vm) {
				write-host "this VM $($this_vm_dir.Name) is already imported"
			} else {
				write-host "importing VM $($this_vm_dir.Name) now."
				$this_vm_guid_path = (gci ($this_vm_dir.FullName + "\" + "Virtual Machines") | where { $_.Name -match ".xml"}).FullName
				if ($this_vm_guid_path) {
					write-host "GUID Path: $($this_vm_guid_path)"
					Import-VM -Path $this_vm_guid_path
				} else {
					write-host "this vm is in an older format. finding GUID a different way."
					$this_vm_guid_path = (gci ($this_vm_dir.FullName + "\" + "Virtual Machines"))[0].FullName
					write-host "GUID Path: $($this_vm_guid_path)"
					Import-VM -Path $this_vm_guid_path
			remove-variable this_vm_dir, this_vm, this_vm_guid_path
		write-host "starting my copy's VMs up now."
		Get-VM | where {$_.Notes -match $critical_tag } | where {$_.State -eq "Off"} | start-vm


Posted in IT | Tagged | Leave a comment

4K Video Down Res

I’ve noticed that all of the 4k videos I’ve taken on my phone or DSLR look super sharp on a 4k screen but don’t always play back the nicest on 1080p screens. So I’ve written a PowerShell script to help convert my videos from 4k to 1080p and 720p. This way I can just grab the appropriate file I need depending on where I’m going to play it back.

Hopefully someone will find this helpful. This seems to work well for me.

You’ll need Handbreak installed to do the conversions. PowerShell is just automating the commands needed to convert each video.

Update 1: The script can now detect if a video was already processed and skips it. This way you can just dump all videos (processed and unprocessed) into the same folder and just run it.

$videoSourcePath = "[my video path]"
gci $videoSourcePath | where {($_.Name -match ".MP4") -or ($_.Name -match ".MOV")} | foreach {
 if (($_.Name -match "-720p30.mp4") -or ($_.Name -match "-1080p30.mp4")) {
 write-host "Skipping already processed video $($_.Name)"
 } else {
 $dst1 = ($_[0].Fullname.Split(".")[0] + "-720p30.mp4")
 $dst2 = ($_[0].Fullname.Split(".")[0] + "-1080p30.mp4")
 write-host "Processing video $($_.Name) @ $(get-date)"
 if (-not (test-path $dst1) ) {
 $args1 = @()
 $args1 += "-i $($_[0].fullname)"
 $args1 += "-o $($dst1)"
 $args1 += '--preset="Fast 720p30"'
 start-process -FilePath "C:\Program Files\HandBrake\HandBrakeCLI.exe" -ArgumentList $args1 -wait
 remove-variable args1
 if (-not (test-path $dst2) ) {
 $args1 = @()
 $args1 += "-i $($_[0].fullname)"
 $args1 += "-o $($dst2)"
 $args1 += '--preset="Fast 1080p30"'
 start-process -FilePath "C:\Program Files\HandBrake\HandBrakeCLI.exe" -ArgumentList $args1 -wait
 remove-variable args1

Posted in IT, Josh Yuhasey | Tagged | Leave a comment