$ErrorActionPreference = 'Stop';

function Test-TaskExists([string]$TaskName) {

	# it is possible to use /TN to get a specific task, but this fails with 
	# an error code of 1, making it indistinguishable from a genuine error
	# So instead filter the output.
	$matchingTasks =
		@(
			& 'schtasks.exe' @('/query', '/fo', 'csv') | 
			ConvertFrom-Csv |
			Where-Object -FilterScript { $_.TaskName -ne 'TaskName' } | # the header is output for every task for some reason
			Select-Object -ExpandProperty 'TaskName' |
			Where-Object -FilterScript { $_.TaskName -match ('^' + [Regex]::Escape($taskName) + '$') }
		)

	if ($LASTEXITCODE -ne 0) {
		throw "Task exists check failed: schtasks.exe execution failed with error code $LASTEXITCODE"
	}

	return ($matchingTasks.Count -gt 0);
}

function New-Task {
	param(
		# Name of the task to create (TN)
		[Parameter(Mandatory=$true)]
		[string]
		$TaskName,

		# Command line to run (TR)
		[Parameter(Mandatory=$true)]
		[string]
		$CommandLine,
		
		# Schedule frequency (SC)
		[Parameter(Mandatory=$true)]
		[ValidateSet('MINUTE', 'HOURLY', 'DAILY', 'WEEKLY', 'MONTHLY', 'ONCE', 'ONSTART', 'ONLOGON', 'ONIDLE', 'ONEVENT')]
		[string]
		$Schedule,

		[string]
		[ValidatePattern('(?i)MON|TUE|WED|THU|FRI|SAT|SUN|[1-9]|[1-2][0-9]|3[0-1]|\*')]#'
		$OnDay,

		# The time at which the task will run (ST)
		[string]
		[ValidatePattern('(?i)[0-2][0-9]:[0-5][0-9]')]#'#'
		$At
	)

	$cmdArgs = @('/Create', '/TN', $TaskName, '/TR', $CommandLine, '/SC', $Schedule, '/RU', 'System');

	$cmdArgs += '/F' # always force, as otherwise the command will prompt for an answer

	if ($OnDay) {
		$cmdArgsargs += '/D', $OnDay
	}

	if ($At) {
		$cmdArgsargs += '/ST', $At
	}

	if ($Force) {
		$cmdArgs += '/F'
	}

	$cmdArgs = @($cmdArgs | Add-ArgumentEscaping)

	#Write-Host $cmdArgs

	& 'schtasks.exe' $cmdArgs
	if ($LASTEXITCODE -ne 0) {
		throw "Task creation failed: schtasks.exe execution failed with error code $LASTEXITCODE"
	}
}

function Add-ArgumentEscaping() {
	param(
		[Parameter(ValueFromPipeline=$true)]
		[string[]]$cmdArguments
	)
	process {
		return ('"' + $_.Replace('"', '\"') + '"')
	}
}