diff --git a/ironicclient/common/base.py b/ironicclient/common/base.py
index 0b11d3480..81305410d 100644
--- a/ironicclient/common/base.py
+++ b/ironicclient/common/base.py
@@ -71,9 +71,9 @@ class Manager(object):
 
         return [obj_class(self, res, loaded=True) for res in data if res]
 
-    def _update(self, url, body, response_key=None):
-        resp, body = self.api.json_request('PATCH', url, body=body)
-        # PATCH requests may not return a body
+    def _update(self, url, body, method='PATCH', response_key=None):
+        resp, body = self.api.json_request(method, url, body=body)
+        # PATCH/PUT requests may not return a body
         if body:
             return self.resource_class(self, body)
 
diff --git a/ironicclient/shell.py b/ironicclient/shell.py
index 3ff4c0fdc..5d253392e 100644
--- a/ironicclient/shell.py
+++ b/ironicclient/shell.py
@@ -23,6 +23,9 @@ import ironicclient
 from ironicclient import client as iroclient
 from ironicclient.common import utils
 from ironicclient import exc
+from ironicclient.openstack.common import gettextutils
+
+gettextutils.install('ironicclient')
 
 
 class IronicShell(object):
diff --git a/ironicclient/tests/v1/test_node.py b/ironicclient/tests/v1/test_node.py
index 926ca7006..d0037ca5c 100644
--- a/ironicclient/tests/v1/test_node.py
+++ b/ironicclient/tests/v1/test_node.py
@@ -36,6 +36,9 @@ PORT = {'id': 456,
         'address': 'AA:AA:AA:AA:AA:AA',
         'extra': {}}
 
+POWER_STATE = {'current': 'power off',
+               'target': 'power on'}
+
 CREATE_NODE = copy.deepcopy(NODE)
 del CREATE_NODE['id']
 del CREATE_NODE['uuid']
@@ -78,6 +81,13 @@ fixtures = {
             {"ports": [PORT]},
         ),
     },
+    '/v1/nodes/%s/state/power' % NODE['uuid']:
+    {
+        'PUT': (
+            {},
+            POWER_STATE,
+        ),
+    },
 }
 
 
@@ -140,3 +150,12 @@ class NodeManagerTest(testtools.TestCase):
         self.assertEqual(len(ports), 1)
         self.assertEqual(ports[0].uuid, PORT['uuid'])
         self.assertEqual(ports[0].address, PORT['address'])
+
+    def test_node_set_power_state(self):
+        power_state = self.mgr.set_power_state(NODE['uuid'], "on")
+        body = {'target': 'power on'}
+        expect = [
+            ('PUT', '/v1/nodes/%s/state/power' % NODE['uuid'], {}, body),
+        ]
+        self.assertEqual(expect, self.api.calls)
+        self.assertEqual('power on', power_state.target)
diff --git a/ironicclient/v1/node.py b/ironicclient/v1/node.py
index eab7e2248..310ff6126 100644
--- a/ironicclient/v1/node.py
+++ b/ironicclient/v1/node.py
@@ -61,3 +61,8 @@ class NodeManager(base.Manager):
 
     def update(self, node_id, patch):
         return self._update(self._path(node_id), patch)
+
+    def set_power_state(self, node_id, state):
+        path = "%s/state/power" % node_id
+        target = {'target': "power %s" % state}
+        return self._update(self._path(path), target, method='PUT')
diff --git a/ironicclient/v1/node_shell.py b/ironicclient/v1/node_shell.py
index 90b7e7c93..d3e4e774a 100644
--- a/ironicclient/v1/node_shell.py
+++ b/ironicclient/v1/node_shell.py
@@ -134,3 +134,22 @@ def do_node_port_list(cc, args):
     field_labels = ['UUID', 'Address']
     fields = ['uuid', 'address']
     utils.print_list(ports, fields, field_labels, sortby=1)
+
+
+@utils.arg('node',
+           metavar='<node id>',
+           help="ID of node")
+@utils.arg('power_state',
+           metavar='<power state>',
+           choices=['on', 'off'],
+           help="Supported states: 'on' or 'off'")
+def do_node_set_power_state(cc, args):
+    """Power the node on or off."""
+    try:
+        state = cc.node.set_power_state(args.node, args.power_state)
+    except exc.HTTPNotFound:
+        raise exc.CommandError(_('Node not found: %s') % args.node)
+
+    field_list = ['current', 'target']
+    data = dict([(f, getattr(state, f, '')) for f in field_list])
+    utils.print_dict(data, wrap=72)