diff --git a/src/backend/port/win32/Makefile b/src/backend/port/win32/Makefile
index 820a3b3..a6ace93 100644
--- a/src/backend/port/win32/Makefile
+++ b/src/backend/port/win32/Makefile
@@ -12,7 +12,7 @@ subdir = src/backend/port/win32
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = timer.o socket.o signal.o security.o mingwcompat.o
+OBJS = timer.o socket.o signal.o mingwcompat.o
 ifeq ($(have_win32_dbghelp), yes)
 OBJS += crashdump.o
 endif
diff --git a/src/backend/port/win32/security.c b/src/backend/port/win32/security.c
index e9cfe15..e69de29 100644
--- a/src/backend/port/win32/security.c
+++ b/src/backend/port/win32/security.c
@@ -1,248 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * security.c
- *	  Microsoft Windows Win32 Security Support Functions
- *
- * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
- *
- * IDENTIFICATION
- *	  src/backend/port/win32/security.c
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres.h"
-
-
-static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token,
-							TOKEN_INFORMATION_CLASS class, char **InfoBuffer,
-							  char *errbuf, int errsize);
-
-/*
- * Returns nonzero if the current user has administrative privileges,
- * or zero if not.
- *
- * Note: this cannot use ereport() because it's called too early during
- * startup.
- */
-int
-pgwin32_is_admin(void)
-{
-	HANDLE		AccessToken;
-	char	   *InfoBuffer = NULL;
-	char		errbuf[256];
-	PTOKEN_GROUPS Groups;
-	PSID		AdministratorsSid;
-	PSID		PowerUsersSid;
-	SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
-	UINT		x;
-	BOOL		success;
-
-	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
-	{
-		write_stderr("could not open process token: error code %lu\n",
-					 GetLastError());
-		exit(1);
-	}
-
-	if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups,
-									   &InfoBuffer, errbuf, sizeof(errbuf)))
-	{
-		write_stderr("%s", errbuf);
-		exit(1);
-	}
-
-	Groups = (PTOKEN_GROUPS) InfoBuffer;
-
-	CloseHandle(AccessToken);
-
-	if (!AllocateAndInitializeSid(&NtAuthority, 2,
-		 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
-								  0, &AdministratorsSid))
-	{
-		write_stderr("could not get SID for Administrators group: error code %lu\n",
-					 GetLastError());
-		exit(1);
-	}
-
-	if (!AllocateAndInitializeSid(&NtAuthority, 2,
-	SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
-								  0, &PowerUsersSid))
-	{
-		write_stderr("could not get SID for PowerUsers group: error code %lu\n",
-					 GetLastError());
-		exit(1);
-	}
-
-	success = FALSE;
-
-	for (x = 0; x < Groups->GroupCount; x++)
-	{
-		if ((EqualSid(AdministratorsSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)) ||
-			(EqualSid(PowerUsersSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)))
-		{
-			success = TRUE;
-			break;
-		}
-	}
-
-	free(InfoBuffer);
-	FreeSid(AdministratorsSid);
-	FreeSid(PowerUsersSid);
-	return success;
-}
-
-/*
- * We consider ourselves running as a service if one of the following is
- * true:
- *
- * 1) We are running as Local System (only used by services)
- * 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
- *	  process token by the SCM when starting a service)
- *
- * Return values:
- *	 0 = Not service
- *	 1 = Service
- *	-1 = Error
- *
- * Note: we can't report errors via either ereport (we're called too early)
- * or write_stderr (because that calls this).  We are therefore reduced to
- * writing directly on stderr, which sucks, but we have few alternatives.
- */
-int
-pgwin32_is_service(void)
-{
-	static int	_is_service = -1;
-	HANDLE		AccessToken;
-	char	   *InfoBuffer = NULL;
-	char		errbuf[256];
-	PTOKEN_GROUPS Groups;
-	PTOKEN_USER User;
-	PSID		ServiceSid;
-	PSID		LocalSystemSid;
-	SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
-	UINT		x;
-
-	/* Only check the first time */
-	if (_is_service != -1)
-		return _is_service;
-
-	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
-	{
-		fprintf(stderr, "could not open process token: error code %lu\n",
-				GetLastError());
-		return -1;
-	}
-
-	/* First check for local system */
-	if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenUser, &InfoBuffer,
-									   errbuf, sizeof(errbuf)))
-	{
-		fprintf(stderr, "%s", errbuf);
-		return -1;
-	}
-
-	User = (PTOKEN_USER) InfoBuffer;
-
-	if (!AllocateAndInitializeSid(&NtAuthority, 1,
-							  SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
-								  &LocalSystemSid))
-	{
-		fprintf(stderr, "could not get SID for local system account\n");
-		CloseHandle(AccessToken);
-		return -1;
-	}
-
-	if (EqualSid(LocalSystemSid, User->User.Sid))
-	{
-		FreeSid(LocalSystemSid);
-		free(InfoBuffer);
-		CloseHandle(AccessToken);
-		_is_service = 1;
-		return _is_service;
-	}
-
-	FreeSid(LocalSystemSid);
-	free(InfoBuffer);
-
-	/* Now check for group SID */
-	if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, &InfoBuffer,
-									   errbuf, sizeof(errbuf)))
-	{
-		fprintf(stderr, "%s", errbuf);
-		return -1;
-	}
-
-	Groups = (PTOKEN_GROUPS) InfoBuffer;
-
-	if (!AllocateAndInitializeSid(&NtAuthority, 1,
-								  SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
-								  &ServiceSid))
-	{
-		fprintf(stderr, "could not get SID for service group\n");
-		free(InfoBuffer);
-		CloseHandle(AccessToken);
-		return -1;
-	}
-
-	_is_service = 0;
-	for (x = 0; x < Groups->GroupCount; x++)
-	{
-		if (EqualSid(ServiceSid, Groups->Groups[x].Sid))
-		{
-			_is_service = 1;
-			break;
-		}
-	}
-
-	free(InfoBuffer);
-	FreeSid(ServiceSid);
-
-	CloseHandle(AccessToken);
-
-	return _is_service;
-}
-
-
-/*
- * Call GetTokenInformation() on a token and return a dynamically sized
- * buffer with the information in it. This buffer must be free():d by
- * the calling function!
- */
-static BOOL
-pgwin32_get_dynamic_tokeninfo(HANDLE token, TOKEN_INFORMATION_CLASS class,
-							  char **InfoBuffer, char *errbuf, int errsize)
-{
-	DWORD		InfoBufferSize;
-
-	if (GetTokenInformation(token, class, NULL, 0, &InfoBufferSize))
-	{
-		snprintf(errbuf, errsize, "could not get token information: got zero size\n");
-		return FALSE;
-	}
-
-	if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
-	{
-		snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
-				 GetLastError());
-		return FALSE;
-	}
-
-	*InfoBuffer = malloc(InfoBufferSize);
-	if (*InfoBuffer == NULL)
-	{
-		snprintf(errbuf, errsize, "could not allocate %d bytes for token information\n",
-				 (int) InfoBufferSize);
-		return FALSE;
-	}
-
-	if (!GetTokenInformation(token, class, *InfoBuffer,
-							 InfoBufferSize, &InfoBufferSize))
-	{
-		snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
-				 GetLastError());
-		return FALSE;
-	}
-
-	return TRUE;
-}
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 6a36d29..d9eca37 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -215,7 +215,7 @@ write_stderr(const char *fmt,...)
 	 * On Win32, we print to stderr if running on a console, or write to
 	 * eventlog if running as a service
 	 */
-	if (!isatty(fileno(stderr)))	/* Running as a service */
+	if (!pgwin32_is_service())	/* Running as a service */
 	{
 		char		errbuf[2048];		/* Arbitrary size? */
 
diff --git a/src/include/port/win32.h b/src/include/port/win32.h
index 4cb51ec..69cd1c4 100644
--- a/src/include/port/win32.h
+++ b/src/include/port/win32.h
@@ -382,9 +382,6 @@ int			pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout);
 
 extern int	pgwin32_noblock;
 
-/* in backend/port/win32/security.c */
-extern int	pgwin32_is_admin(void);
-extern int	pgwin32_is_service(void);
 #endif
 
 /* in backend/port/win32_shmem.c */
@@ -400,6 +397,10 @@ extern void _dosmaperr(unsigned long);
 extern int	pgwin32_putenv(const char *);
 extern void pgwin32_unsetenv(const char *);
 
+/* in port/win32security.c */
+extern int	pgwin32_is_service(void);
+extern int	pgwin32_is_admin(void);
+
 #define putenv(x) pgwin32_putenv(x)
 #define unsetenv(x) pgwin32_unsetenv(x)
 
diff --git a/src/backend/port/win32/security.c b/src/port/win32security.c
similarity index 85%
copy from src/backend/port/win32/security.c
copy to src/port/win32security.c
index e9cfe15..a6d8287 100644
--- a/src/backend/port/win32/security.c
+++ b/src/port/win32security.c
@@ -1,22 +1,26 @@
 /*-------------------------------------------------------------------------
  *
- * security.c
+ * win32security.c
  *	  Microsoft Windows Win32 Security Support Functions
  *
  * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  src/backend/port/win32/security.c
+ *	  src/port/win32security.c
  *
  *-------------------------------------------------------------------------
  */
 
+#ifndef FRONTEND
 #include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
 
 
 static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token,
-							TOKEN_INFORMATION_CLASS class, char **InfoBuffer,
-							  char *errbuf, int errsize);
+							  TOKEN_INFORMATION_CLASS class,
+							  char **InfoBuffer, char *errbuf, int errsize);
 
 /*
  * Returns nonzero if the current user has administrative privileges,
@@ -40,15 +44,24 @@ pgwin32_is_admin(void)
 
 	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
 	{
+#ifndef FRONTEND
 		write_stderr("could not open process token: error code %lu\n",
 					 GetLastError());
+#else
+		fprintf(stderr, "could not open process token: error code %lu\n",
+				GetLastError());
+#endif
 		exit(1);
 	}
 
 	if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups,
 									   &InfoBuffer, errbuf, sizeof(errbuf)))
 	{
+#ifndef FRONTEND
 		write_stderr("%s", errbuf);
+#else
+		fprintf(stderr, "%s", errbuf);
+#endif
 		exit(1);
 	}
 
@@ -60,8 +73,14 @@ pgwin32_is_admin(void)
 		 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
 								  0, &AdministratorsSid))
 	{
+#ifndef FRONTEND
 		write_stderr("could not get SID for Administrators group: error code %lu\n",
 					 GetLastError());
+#else
+		fprintf(stderr,
+			"could not get SID for Administrators group: error code %lu\n",
+			GetLastError());
+#endif
 		exit(1);
 	}
 
@@ -69,8 +88,14 @@ pgwin32_is_admin(void)
 	SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
 								  0, &PowerUsersSid))
 	{
+#ifndef FRONTEND
 		write_stderr("could not get SID for PowerUsers group: error code %lu\n",
 					 GetLastError());
+#else
+		fprintf(stderr,
+			"could not get SID for PowerUsers group: error code %lu\n",
+			GetLastError());
+#endif
 		exit(1);
 	}
 
@@ -92,6 +117,7 @@ pgwin32_is_admin(void)
 	return success;
 }
 
+
 /*
  * We consider ourselves running as a service if one of the following is
  * true:
@@ -105,9 +131,11 @@ pgwin32_is_admin(void)
  *	 1 = Service
  *	-1 = Error
  *
- * Note: we can't report errors via either ereport (we're called too early)
- * or write_stderr (because that calls this).  We are therefore reduced to
- * writing directly on stderr, which sucks, but we have few alternatives.
+ * Note: we can't report errors via either ereport (we're called too early
+ * in the backend) or write_stderr (because that calls this).  We are
+ * therefore reduced to writing directly on stderr, which sucks, but we
+ * have few alternatives. Backend-side code needs as well calls to write
+ * directly to stderr, so that's not something to worry about in this case.
  */
 int
 pgwin32_is_service(void)
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 3abbb4c..224fdcd 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -89,7 +89,7 @@ sub mkvcbuild
 	  pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c
 	  mkdtemp.c qsort.c qsort_arg.c quotes.c system.c
 	  sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c
-	  win32env.c win32error.c win32setlocale.c);
+	  win32env.c win32error.c win32security.c win32setlocale.c);
 
 	push(@pgportfiles, 'rint.c') if ($vsVersion < '12.00');
 
