diff --git a/lib/backend.py b/lib/backend.py
index 0a3f2dc8942169652f3e81b4ed6a37f51160ced1..4aa851fffeb9247e5a44da28078ebfd114a07b0f 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -711,7 +711,7 @@ def VerifyNode(what, cluster_name):
   if constants.NV_USERSCRIPTS in what:
     result[constants.NV_USERSCRIPTS] = \
       [script for script in what[constants.NV_USERSCRIPTS]
-       if not (os.path.exists(script) and os.access(script, os.X_OK))]
+       if not utils.IsExecutable(script)]
 
   if constants.NV_OOB_PATHS in what:
     result[constants.NV_OOB_PATHS] = tmp = []
diff --git a/lib/utils/process.py b/lib/utils/process.py
index e56932f9c17784a998853989ab3d10064adbe0ff..243151f32deb79dc5c9a47cc4abe0e0c001d378c 100644
--- a/lib/utils/process.py
+++ b/lib/utils/process.py
@@ -718,8 +718,8 @@ def RunParts(dir_name, env=None, reset_env=False):
 
   for relname in sorted(dir_contents):
     fname = utils_io.PathJoin(dir_name, relname)
-    if not (os.path.isfile(fname) and os.access(fname, os.X_OK) and
-            constants.EXT_PLUGIN_MASK.match(relname) is not None):
+    if not (constants.EXT_PLUGIN_MASK.match(relname) is not None and
+            utils_wrapper.IsExecutable(fname)):
       rr.append((relname, constants.RUNPARTS_SKIP, None))
     else:
       try:
diff --git a/lib/utils/wrapper.py b/lib/utils/wrapper.py
index 982971e71f841ad84a21a063db829382bf373765..3b6f6f3dddf0a4b05d1b8dc3f5e585a60f576bb8 100644
--- a/lib/utils/wrapper.py
+++ b/lib/utils/wrapper.py
@@ -172,6 +172,17 @@ def GetClosedTempfile(*args, **kwargs):
   return path
 
 
+def IsExecutable(filename):
+  """Checks whether a file exists and is executable.
+
+  @type filename: string
+  @param filename: Filename
+  @rtype: bool
+
+  """
+  return os.path.isfile(filename) and os.access(filename, os.X_OK)
+
+
 def ResetTempfileModule(_time=time.time):
   """Resets the random name generator of the tempfile module.
 
diff --git a/test/ganeti.utils.wrapper_unittest.py b/test/ganeti.utils.wrapper_unittest.py
index 16633f7a2b6a18c5ebfb7950278ec67eee32aa3a..cfdae9a15f72f4418477e774e368be0fc3570ada 100755
--- a/test/ganeti.utils.wrapper_unittest.py
+++ b/test/ganeti.utils.wrapper_unittest.py
@@ -27,6 +27,7 @@ import os
 import socket
 import tempfile
 import unittest
+import shutil
 
 from ganeti import constants
 from ganeti import utils
@@ -122,5 +123,50 @@ class TestIgnoreSignals(unittest.TestCase):
     self.assertEquals(utils.IgnoreSignals(self._Return, 33), 33)
 
 
+class TestIsExecutable(unittest.TestCase):
+  def setUp(self):
+    self.tmpdir = tempfile.mkdtemp()
+
+  def tearDown(self):
+    shutil.rmtree(self.tmpdir)
+
+  def testNonExisting(self):
+    fname = utils.PathJoin(self.tmpdir, "file")
+    assert not os.path.exists(fname)
+    self.assertFalse(utils.IsExecutable(fname))
+
+  def testNoFile(self):
+    path = utils.PathJoin(self.tmpdir, "something")
+    os.mkdir(path)
+    assert os.path.isdir(path)
+    self.assertFalse(utils.IsExecutable(path))
+
+  def testExecutable(self):
+    fname = utils.PathJoin(self.tmpdir, "file")
+    utils.WriteFile(fname, data="#!/bin/bash", mode=0700)
+    assert os.path.exists(fname)
+    self.assertTrue(utils.IsExecutable(fname))
+
+    self.assertTrue(self._TestSymlink(fname))
+
+  def testFileNotExecutable(self):
+    fname = utils.PathJoin(self.tmpdir, "file")
+    utils.WriteFile(fname, data="#!/bin/bash", mode=0600)
+    assert os.path.exists(fname)
+    self.assertFalse(utils.IsExecutable(fname))
+
+    self.assertFalse(self._TestSymlink(fname))
+
+  def _TestSymlink(self, fname):
+    assert os.path.exists(fname)
+
+    linkname = utils.PathJoin(self.tmpdir, "cmd")
+    os.symlink(fname, linkname)
+
+    assert os.path.islink(linkname)
+
+    return utils.IsExecutable(linkname)
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()