-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.xml
1015 lines (790 loc) · 152 KB
/
index.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Estyn's Blog</title>
<link>http://estynedwards.com/</link>
<description>Recent content on Estyn's Blog</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Tue, 17 May 2016 00:00:00 +0000</lastBuildDate>
<atom:link href="http://estynedwards.com/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>ng-conf 2016</title>
<link>http://estynedwards.com/blog/2016/05/17/NGConf/</link>
<pubDate>Tue, 17 May 2016 00:00:00 +0000</pubDate>
<guid>http://estynedwards.com/blog/2016/05/17/NGConf/</guid>
<description>
<p>I was lucky enough to get a ticket to ng-cong in Salt Lake City this year. It was a great conference, much different from the tech conferences that I&rsquo;m used to.</p>
<h1 id="key-take-aways:677625b794d2b5469be210d3c913a38a">Key Take Aways</h1>
<ul>
<li>Angular 2 is going to be fast
<ul>
<li>The RC file size has been reduced from 170k to 50k.<br /></li>
<li>Angular CLI will support pre-compilation of templates which will help with both file size and time to initial load.</li>
<li>Lazy loading on routes will further help with load times</li>
<li>Angular Universal will allow pre-rendering of angular sites on the server (supports Node and asp.net via node)</li>
<li>Angular 2 change detection is fast!</li>
</ul></li>
<li>Angular 2 is going to be everywhere
<ul>
<li>Technologies like ionic and native script will allow angular 2 to run on mobile devices</li>
<li>Mobile.angular.io provides tooling for better progressive web applications</li>
<li>Angular Universal will allow angular to run on the server</li>
<li>Desktop apps can be created with Electron and Angular 2</li>
</ul></li>
<li>Angular 2 is going to have a huge ecosystem
<ul>
<li>Angular Material is going to provide a rich UI component suite</li>
<li>3rd Party components are coming (<a href="http://wijmo.com/angular2/">Wijimo</a>, <a href="https://vaadin.com/vaadin-documentation-portlet/elements/integrations/angular2.html">Vaadin</a>, <a href="http://demos.telerik.com/kendo-ui/integration/angular2">Kendo</a>, <a href="https://github.com/ng-bootstrap/core">Ng-bootstrap</a> and others)</li>
</ul></li>
<li>TypeScript all the things
<ul>
<li>TypeScript is going to be the best way to write angular code</li>
<li>Consider using TypeScript for any js code</li>
</ul></li>
</ul>
<h1 id="tips:677625b794d2b5469be210d3c913a38a">Tips</h1>
<ul>
<li>Talk with fellow attendees, some of the best information you will get will be from other attendees</li>
<li>Pre-download workshop files the wi-fi doesn&rsquo;t handle 100 npm install at once very well</li>
<li>Go early or late for food avoid the lines</li>
<li>I found it interesting that most presenters were using a Macbook Pro (Apple), angular (Google) and VScode and typescript (Microsoft). It&rsquo;s nice to see everyone playing nice together.</li>
</ul>
<h1 id="conclusion:677625b794d2b5469be210d3c913a38a">Conclusion</h1>
<p>Overall I thought this was a very well run conference, my only negative feedback would be that a few of the talks seemed to be duplicating content which doesn&rsquo;t really make sense in a single track conference.</p>
</description>
</item>
<item>
<title>EPark</title>
<link>http://estynedwards.com/blog/2016/02/29/Epark-part1/</link>
<pubDate>Mon, 29 Feb 2016 00:00:00 +0000</pubDate>
<guid>http://estynedwards.com/blog/2016/02/29/Epark-part1/</guid>
<description>
<ul>
<li>Part 1 - EPark</li>
<li>Part 2 - EPark Rebuilt (Coming Soon)</li>
</ul>
<p>The City of Edmonton has removed all the parking meters and replaced them with an electronic parking system called EPark. The EPark system allows you to pay at either a kiosk or through your mobile phone, which sounds awesome until you try to use the mobile app. EPark is an example of an application that had no usability testing done and very little thought put in to how users will use the application, which explains it&rsquo;s one star ratting in the app store. In this post we will investigate some of the issues, in part two we will look at some solutions.</p>
<h1 id="login-screen:92b37e91336f08c8446f4bf574729975">Login Screen</h1>
<p>Login screens are very common in both mobile and web applications and the layout of a login screen is fairly standard. Login screens are a solved problem, they consisting of a user name, password and login button. EPark almost does this right, but in addition to having a login button it has a reset button and bizarrely it places the reset button first.</p>
<p><img src="../Login.png" width=250/></p>
<p>In fact the login button doesn&rsquo;t show up on many mobile devices without scrolling making the login process particularly confusing. The reset button is completely unnecessary and I would argue that the remember username is also not needed. Simplifying the user interface would make login in easier for users.</p>
<h1 id="user-onboarding:92b37e91336f08c8446f4bf574729975">User Onboarding</h1>
<p>The create account link creates a modal dialog which is generally a bad idea on mobile, and is a particularly bad choice when it is long enough to require scrolling. In this case a dedicated screen would be a better choice.</p>
<p><img src="../phone1.png" width=250/>
<img src="../phone2.png" width=250/></p>
<p>The sign-up process doesn&rsquo;t prompt the user to add a mobile number or a license plate which is unfortunate as they are both required to use the system. I would rather see a wizard that would walk the user through the account creation process.</p>
<h1 id="mobile-number-account-confusion:92b37e91336f08c8446f4bf574729975">Mobile Number / Account Confusion</h1>
<p>I have a hard time understanding why the system allows multiple mobile numbers the way they do. The mobile number also include settings around when to send reminders (even email reminders). It&rsquo;s good that these settings exist, but it would make a lot more sense for these to exist on an account basis not a per number basis. The majority of users will have a single phone number and for those users that have multiple numbers it seems likely that they will want the same notification rules on both numbers.</p>
<p>It seems like they are using phone number to allow multiple users to share they same account, perhaps for business use, but this means that all the users sharing the account will share the same user name and password and will have permission to edit the other users. A better implementation would allow for separate user accounts that could share the same funds and have an administrator who could manage the overall account.</p>
<h1 id="license-plate:92b37e91336f08c8446f4bf574729975">License Plate</h1>
<p>The license plate entry is thankfully fairly straight forward, although the small vehicle promotion is problematic. The only additional confusion is the fact that license plates must be globally unique. This means that if a couple has two cars they cannot both have both cars on their accounts. It also means that I could in theory register someone elses car and prevent them from using the system.</p>
<h2 id="small-vehicle-promotion:92b37e91336f08c8446f4bf574729975">Small Vehicle Promotion</h2>
<p>If a vehicle is under a certain size it qualifies for a discount, unfortunately they do not say what size that is. If you try to save a vehicle with a size that is too large they display and error message, but frustratingly the error message also doesn&rsquo;t display the size that is required. The only way to find out what size is required is to click on the question mark next to the promotion which then popups a non-dismissible modal.</p>
<p><img src="../Small Vehicle.png" width=250/></p>
<p>An additional frustration around the small vehicle discount is that the field is disabled if you have more than one license plate. There is no indication in the UI why the field is disabled, but if you have more than one license plate you cannot edit the field. I though the app was broken until I read the documentation.</p>
<h1 id="ui-improvements:92b37e91336f08c8446f4bf574729975">UI Improvements</h1>
<p>There are several places where small changes to the UI could lead to significant improvements, currently the app feels unfinished.</p>
<h3 id="error-message-text:92b37e91336f08c8446f4bf574729975">Error Message Text</h3>
<p>This is the problem that sparked this blog post. When I was trying to start a session and I kept getting the following error message:</p>
<blockquote>
<p>Could not activate your session; an invalid phone number was supplied.</p>
</blockquote>
<p>After much frustration it turns out that my license plate was incorrect, not my phone number. The error message makes no sense and was clearly not tested properly. It&rsquo;s particularly frustrating as the phone number is displaced right on the screen.</p>
<p><img src="../Invalid phone number.png" width=250/></p>
<h3 id="error-messages:92b37e91336f08c8446f4bf574729975">Error Messages</h3>
<p>The error messages popup over the UI and there isn&rsquo;t any way to dismiss them or access the UI underneath them. They do eventually disappear (after 20 or so seconds), but not before confusing and frustrating the user.</p>
<h3 id="logo:92b37e91336f08c8446f4bf574729975">Logo</h3>
<p>This feels a little nitpicky, but why is the EPark logo fuzzy? Could they not use a photo with the proper resolution?</p>
<h3 id="workflow:92b37e91336f08c8446f4bf574729975">Workflow</h3>
<p>If an account has only one mobile number and license plate then we can stream line the process to avoid prompting for this information.</p>
<h3 id="zoom:92b37e91336f08c8446f4bf574729975">Zoom</h3>
<p>If you accidentally pinch or double-click in the UI it zooms in like a webpage. It is quite confusing and serves no purpose. This can (and should) be disabled in mobile apps that are acting as native apps.</p>
<h3 id="dialogs:92b37e91336f08c8446f4bf574729975">Dialogs</h3>
<p>When you start a session the dialog message title is &ldquo;startstop.html&rdquo; not only is that not useful to users it is incredibly sloppy.<br/>
<img src="../Bad Dialog.png" width=250/></p>
</description>
</item>
<item>
<title>Using IdentityServer 4 with ServiceStack and Angular</title>
<link>http://estynedwards.com/blog/2016/01/30/ServiceStack-IdentityServer-Angular/</link>
<pubDate>Sat, 30 Jan 2016 00:00:00 +0000</pubDate>
<guid>http://estynedwards.com/blog/2016/01/30/ServiceStack-IdentityServer-Angular/</guid>
<description>
<p>We&rsquo;ve looking to use a custom OAuth/OpenID provider for a few of our projects and after reviewing the options available we decided to use Identity Server as it looked to be the most stable and feature rich. Currently we use ServiceStack for our backend and while ServiceStack has build in support for OAuth and OpenID it doesn&rsquo;t appear to have any support for OpenId Connect. And while we will be using OAuth tokens we will be using the OpenId Connect configuration endpoints for configuration.</p>
<h1 id="step-1-setup-identity-server:0c891f9681739990127d39f58407d9b9">Step 1: Setup Identity Server</h1>
<p>I&rsquo;m not going to go into too much detail here as there are plenty of good tutorials and blog posts on how to setup identity server already. We chose to go with Identity Server 4 as it runs on asp.net core.</p>
<p>Here is the code I used to configure Identity Server:
<div class="highlight"><pre> <span class="k">public</span> <span class="k">void</span> <span class="nf">ConfigureServices</span><span class="p">(</span><span class="n">IServiceCollection</span> <span class="n">services</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">//TODO: This is the demo cert, replace with our own</span>
<span class="kt">var</span> <span class="n">cert</span> <span class="p">=</span> <span class="k">new</span> <span class="n">X509Certificate2</span><span class="p">(</span><span class="n">Path</span><span class="p">.</span><span class="n">Combine</span><span class="p">(</span><span class="n">_environment</span><span class="p">.</span><span class="n">ApplicationBasePath</span><span class="p">,</span> <span class="s">&quot;idsrv4test.pfx&quot;</span><span class="p">),</span> <span class="s">&quot;idsrv3test&quot;</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">services</span><span class="p">.</span><span class="n">AddIdentityServer</span><span class="p">(</span><span class="n">options</span> <span class="p">=&gt;</span>
<span class="p">{</span>
<span class="n">options</span><span class="p">.</span><span class="n">SigningCertificate</span> <span class="p">=</span> <span class="n">cert</span><span class="p">;</span>
<span class="n">options</span><span class="p">.</span><span class="n">SiteName</span> <span class="p">=</span> <span class="s">&quot;Punchcard Identity Server (STS)&quot;</span><span class="p">;</span>
<span class="p">});</span>
<span class="n">builder</span><span class="p">.</span><span class="n">AddInMemoryClients</span><span class="p">(</span><span class="n">Clients</span><span class="p">.</span><span class="n">Get</span><span class="p">());</span>
<span class="n">builder</span><span class="p">.</span><span class="n">AddInMemoryScopes</span><span class="p">(</span><span class="n">Scopes</span><span class="p">.</span><span class="n">Get</span><span class="p">());</span>
<span class="n">builder</span><span class="p">.</span><span class="n">AddInMemoryUsers</span><span class="p">(</span><span class="n">Users</span><span class="p">.</span><span class="n">Get</span><span class="p">());</span>
<span class="n">builder</span><span class="p">.</span><span class="n">AddCustomGrantValidator</span><span class="p">&lt;</span><span class="n">CustomGrantValidator</span><span class="p">&gt;();</span>
<span class="c1">// for the UI</span>
<span class="n">services</span>
<span class="p">.</span><span class="n">AddMvc</span><span class="p">()</span>
<span class="p">.</span><span class="n">AddRazorOptions</span><span class="p">(</span><span class="n">razor</span> <span class="p">=&gt;</span>
<span class="p">{</span>
<span class="n">razor</span><span class="p">.</span><span class="n">ViewLocationExpanders</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">IdSvrHost</span><span class="p">.</span><span class="n">UI</span><span class="p">.</span><span class="n">CustomViewLocationExpander</span><span class="p">());</span>
<span class="p">});</span>
<span class="n">services</span><span class="p">.</span><span class="n">AddTransient</span><span class="p">&lt;</span><span class="n">IdSvrHost</span><span class="p">.</span><span class="n">UI</span><span class="p">.</span><span class="n">Login</span><span class="p">.</span><span class="n">LoginService</span><span class="p">&gt;();</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Configure</span><span class="p">(</span><span class="n">IApplicationBuilder</span> <span class="n">app</span><span class="p">,</span> <span class="n">ILoggerFactory</span> <span class="n">loggerFactory</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">loggerFactory</span><span class="p">.</span><span class="n">AddConsole</span><span class="p">(</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Verbose</span><span class="p">);</span>
<span class="n">loggerFactory</span><span class="p">.</span><span class="n">AddDebug</span><span class="p">(</span><span class="n">LogLevel</span><span class="p">.</span><span class="n">Verbose</span><span class="p">);</span>
<span class="c1">// For Test only change in prod</span>
<span class="n">app</span><span class="p">.</span><span class="n">UseCors</span><span class="p">(</span><span class="n">builder</span> <span class="p">=&gt;</span>
<span class="n">builder</span><span class="p">.</span><span class="n">AllowAnyOrigin</span><span class="p">().</span><span class="n">AllowAnyHeader</span><span class="p">().</span><span class="n">AllowAnyMethod</span><span class="p">().</span><span class="n">AllowCredentials</span><span class="p">());</span>
<span class="n">app</span><span class="p">.</span><span class="n">UseDeveloperExceptionPage</span><span class="p">();</span>
<span class="n">app</span><span class="p">.</span><span class="n">UseIISPlatformHandler</span><span class="p">();</span>
<span class="n">app</span><span class="p">.</span><span class="n">UseIdentityServer</span><span class="p">();</span>
<span class="n">app</span><span class="p">.</span><span class="n">UseStaticFiles</span><span class="p">();</span>
<span class="n">app</span><span class="p">.</span><span class="n">UseMvcWithDefaultRoute</span><span class="p">();</span>
<span class="p">}</span>
</pre></div>
</p>
<p>And the client configuration for identity server:
<div class="highlight"><pre> <span class="c1">///////////////////////////////////////////</span>
<span class="c1">// JS OIDC Sample</span>
<span class="c1">//////////////////////////////////////////</span>
<span class="k">new</span> <span class="n">Client</span>
<span class="p">{</span>
<span class="n">ClientId</span> <span class="p">=</span> <span class="s">&quot;js_oidc&quot;</span><span class="p">,</span>
<span class="n">ClientName</span> <span class="p">=</span> <span class="s">&quot;JavaScript OIDC Client&quot;</span><span class="p">,</span>
<span class="n">ClientUri</span> <span class="p">=</span> <span class="s">&quot;http://identityserver.io&quot;</span><span class="p">,</span>
<span class="n">Flow</span> <span class="p">=</span> <span class="n">Flows</span><span class="p">.</span><span class="n">Implicit</span><span class="p">,</span>
<span class="n">RedirectUris</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span>
<span class="p">{</span>
<span class="s">&quot;http://localhost:7017/index.html&quot;</span><span class="p">,</span>
<span class="s">&quot;http://localhost:7017/silent_renew.html&quot;</span><span class="p">,</span>
<span class="s">&quot;http://localhost:7200/callback.html&quot;</span>
<span class="p">},</span>
<span class="n">PostLogoutRedirectUris</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span>
<span class="p">{</span>
<span class="s">&quot;http://localhost:7017/index.html&quot;</span><span class="p">,</span>
<span class="p">},</span>
<span class="n">AllowedCorsOrigins</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span>
<span class="p">{</span>
<span class="s">&quot;http://localhost:7017&quot;</span><span class="p">,</span><span class="s">&quot;*&quot;</span>
<span class="p">},</span>
<span class="n">AllowedScopes</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span>
<span class="p">{</span>
<span class="n">StandardScopes</span><span class="p">.</span><span class="n">OpenId</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
<span class="n">StandardScopes</span><span class="p">.</span><span class="n">Profile</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
<span class="n">StandardScopes</span><span class="p">.</span><span class="n">Email</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
<span class="n">StandardScopes</span><span class="p">.</span><span class="n">Roles</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
<span class="s">&quot;api1&quot;</span><span class="p">,</span> <span class="s">&quot;api2&quot;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</p>
<h1 id="step-2-create-a-custom-authprovider-for-servicestack:0c891f9681739990127d39f58407d9b9">Step 2: Create a custom authprovider for ServiceStack</h1>
<p>Next we created a custom Authentication Provider for Service Stack. We plan on using the code in several different project so we&rsquo;d like the amount of configuration neccessary to use the provider to be minimal. Luckily OpenID Connect provieds a discovery endpoint that can be used to retrieve the configuration from the server (including the public certificate).</p>
<p>The goald is only have to provide the url of the discovery endpoint in order to use the provider.
<div class="highlight"><pre> <span class="n">Plugins</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">AuthFeature</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="k">new</span> <span class="n">AuthUserSession</span><span class="p">(),</span>
<span class="k">new</span> <span class="n">IAuthProvider</span><span class="p">[]</span> <span class="p">{</span>
<span class="k">new</span> <span class="nf">JsonWebTokenAuthProvider</span><span class="p">(</span><span class="s">&quot;http://localhost:22530/&quot;</span> <span class="p">+</span> <span class="s">&quot;.well-known/openid-configuration&quot;</span><span class="p">,</span> <span class="s">&quot;http://localhost:22530/resources&quot;</span><span class="p">),</span>
<span class="p">}));</span>
</pre></div>
</p>
<p><div class="highlight"><pre> <span class="k">public</span> <span class="k">class</span> <span class="nc">JsonWebTokenAuthProvider</span> <span class="p">:</span> <span class="n">AuthProvider</span><span class="p">,</span> <span class="n">IAuthWithRequest</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">=</span> <span class="s">&quot;JWT&quot;</span><span class="p">;</span>
<span class="k">private</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">Realm</span> <span class="p">=</span> <span class="s">&quot;/auth/JWT&quot;</span><span class="p">;</span>
<span class="k">private</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">MissingAuthHeader</span> <span class="p">=</span> <span class="s">&quot;Missing Authorization Header&quot;</span><span class="p">;</span>
<span class="k">private</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">InvalidAuthHeader</span> <span class="p">=</span> <span class="s">&quot;Invalid Authorization Header&quot;</span><span class="p">;</span>
<span class="k">private</span> <span class="kt">string</span> <span class="n">Audience</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="k">private</span> <span class="kt">string</span> <span class="n">Issuer</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="k">private</span> <span class="n">X509Certificate2</span> <span class="n">Certificate</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="c1">/// &lt;summary&gt;</span>
<span class="c1">/// Creates a new JsonWebToken Auth Provider</span>
<span class="c1">/// &lt;/summary&gt;</span>
<span class="c1">/// &lt;param name=&quot;discoveryEndpoint&quot;&gt;aThe url to get the configuration informaion from.. (er &quot;http://localhost:22530/&quot; + &quot;.well-known/openid-configuration&quot;)&lt;/param&gt;</span>
<span class="c1">/// &lt;param name=&quot;audience&quot;&gt;The client for openID (eg js_oidc)&lt;/param&gt;</span>
<span class="k">public</span> <span class="nf">JsonWebTokenAuthProvider</span><span class="p">(</span><span class="kt">string</span> <span class="n">discoveryEndpoint</span><span class="p">,</span> <span class="kt">string</span> <span class="n">audience</span> <span class="p">=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Provider</span> <span class="p">=</span> <span class="n">Name</span><span class="p">;</span>
<span class="n">AuthRealm</span> <span class="p">=</span> <span class="n">Realm</span><span class="p">;</span>
<span class="n">Audience</span> <span class="p">=</span> <span class="n">audience</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">configurationManager</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ConfigurationManager</span><span class="p">&lt;</span><span class="n">OpenIdConnectConfiguration</span><span class="p">&gt;(</span><span class="n">discoveryEndpoint</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">config</span> <span class="p">=</span> <span class="n">configurationManager</span><span class="p">.</span><span class="n">GetConfigurationAsync</span><span class="p">().</span><span class="n">Result</span><span class="p">;</span>
<span class="n">Certificate</span> <span class="p">=</span> <span class="k">new</span> <span class="n">X509Certificate2</span><span class="p">(</span><span class="n">Convert</span><span class="p">.</span><span class="n">FromBase64String</span><span class="p">(</span><span class="n">config</span><span class="p">.</span><span class="n">JsonWebKeySet</span><span class="p">.</span><span class="n">Keys</span><span class="p">.</span><span class="n">First</span><span class="p">().</span><span class="n">X5c</span><span class="p">.</span><span class="n">First</span><span class="p">()));</span>
<span class="n">Issuer</span> <span class="p">=</span> <span class="n">config</span><span class="p">.</span><span class="n">Issuer</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="kt">object</span> <span class="nf">Authenticate</span><span class="p">(</span><span class="n">IServiceBase</span> <span class="n">authService</span><span class="p">,</span> <span class="n">IAuthSession</span> <span class="n">session</span><span class="p">,</span> <span class="n">Authenticate</span> <span class="n">request</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">header</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">oauth_token</span><span class="p">;</span>
<span class="c1">// if no auth header, 401</span>
<span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="n">IsNullOrEmpty</span><span class="p">(</span><span class="n">header</span><span class="p">))</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="n">HttpError</span><span class="p">.</span><span class="n">Unauthorized</span><span class="p">(</span><span class="n">MissingAuthHeader</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">var</span> <span class="n">headerData</span> <span class="p">=</span> <span class="n">header</span><span class="p">.</span><span class="n">Split</span><span class="p">(</span><span class="sc">&#39; &#39;</span><span class="p">);</span>
<span class="c1">// if header is missing bearer portion, 401</span>
<span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="n">Compare</span><span class="p">(</span><span class="n">headerData</span><span class="p">[</span><span class="m">0</span><span class="p">],</span> <span class="s">&quot;BEARER&quot;</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">OrdinalIgnoreCase</span><span class="p">)</span> <span class="p">!=</span> <span class="m">0</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="n">HttpError</span><span class="p">.</span><span class="n">Unauthorized</span><span class="p">(</span><span class="n">InvalidAuthHeader</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="c1">// set current principal to the validated token principal</span>
<span class="n">Thread</span><span class="p">.</span><span class="n">CurrentPrincipal</span> <span class="p">=</span> <span class="n">JsonWebToken</span><span class="p">.</span><span class="n">ValidateToken</span><span class="p">(</span><span class="n">headerData</span><span class="p">[</span><span class="m">1</span><span class="p">],</span> <span class="n">Certificate</span><span class="p">,</span> <span class="n">Audience</span><span class="p">,</span> <span class="n">Issuer</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">HttpContext</span><span class="p">.</span><span class="n">Current</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// set the current request&#39;s user the the decoded principal</span>
<span class="n">HttpContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">User</span> <span class="p">=</span> <span class="n">Thread</span><span class="p">.</span><span class="n">CurrentPrincipal</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// set the session&#39;s username to the logged in user</span>
<span class="n">session</span><span class="p">.</span><span class="n">UserName</span> <span class="p">=</span> <span class="n">Thread</span><span class="p">.</span><span class="n">CurrentPrincipal</span><span class="p">.</span><span class="n">Identity</span><span class="p">.</span><span class="n">Name</span><span class="p">;</span>
<span class="k">return</span> <span class="nf">OnAuthenticated</span><span class="p">(</span><span class="n">authService</span><span class="p">,</span> <span class="n">session</span><span class="p">,</span> <span class="k">new</span> <span class="n">AuthTokens</span><span class="p">(),</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;());</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">HttpError</span><span class="p">(</span><span class="n">HttpStatusCode</span><span class="p">.</span><span class="n">Unauthorized</span><span class="p">,</span> <span class="n">ex</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">/// &lt;param name=&quot;session&quot;&gt;&lt;/param&gt;</span>
<span class="c1">/// &lt;param name=&quot;tokens&quot;&gt;&lt;/param&gt;</span>
<span class="c1">/// &lt;param name=&quot;request&quot;&gt;&lt;/param&gt;</span>
<span class="c1">/// &lt;returns&gt;&lt;/returns&gt;</span>
<span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="nf">IsAuthorized</span><span class="p">(</span><span class="n">IAuthSession</span> <span class="n">session</span><span class="p">,</span> <span class="n">IAuthTokens</span> <span class="n">tokens</span><span class="p">,</span> <span class="n">Authenticate</span> <span class="n">request</span> <span class="p">=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">HttpContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">User</span><span class="p">.</span><span class="n">Identity</span><span class="p">.</span><span class="n">IsAuthenticated</span> <span class="p">&amp;&amp;</span> <span class="n">session</span><span class="p">.</span><span class="n">IsAuthenticated</span> <span class="p">&amp;&amp;</span> <span class="kt">string</span><span class="p">.</span><span class="n">Equals</span><span class="p">(</span><span class="n">session</span><span class="p">.</span><span class="n">UserName</span><span class="p">,</span> <span class="n">HttpContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">User</span><span class="p">.</span><span class="n">Identity</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">OrdinalIgnoreCase</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">PreAuthenticate</span><span class="p">(</span><span class="n">IRequest</span> <span class="n">request</span><span class="p">,</span> <span class="n">IResponse</span> <span class="n">response</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">header</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">Headers</span><span class="p">[</span><span class="s">&quot;Authorization&quot;</span><span class="p">];</span>
<span class="kt">var</span> <span class="n">authService</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="n">TryResolve</span><span class="p">&lt;</span><span class="n">AuthenticateService</span><span class="p">&gt;();</span>
<span class="n">authService</span><span class="p">.</span><span class="n">Request</span> <span class="p">=</span> <span class="n">request</span><span class="p">;</span>
<span class="c1">// pass auth header in as oauth token to authentication</span>
<span class="n">authService</span><span class="p">.</span><span class="n">Post</span><span class="p">(</span><span class="k">new</span> <span class="n">Authenticate</span>
<span class="p">{</span>
<span class="n">provider</span> <span class="p">=</span> <span class="n">Name</span><span class="p">,</span>
<span class="n">oauth_token</span> <span class="p">=</span> <span class="n">header</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</p>
<p>We use the following class to handle the decoding and validating of the token&rdquo;</p>
<p><div class="highlight"><pre>
<span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">JsonWebToken</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">NameClaimType</span> <span class="p">=</span> <span class="s">&quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name&quot;</span><span class="p">;</span>
<span class="k">private</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">RoleClaimType</span> <span class="p">=</span> <span class="s">&quot;http://schemas.microsoft.com/ws/2008/06/identity/claims/role&quot;</span><span class="p">;</span>
<span class="k">private</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">ActorClaimType</span> <span class="p">=</span> <span class="s">&quot;http://schemas.xmlsoap.org/ws/2009/09/identity/claims/actor&quot;</span><span class="p">;</span>
<span class="k">private</span> <span class="k">const</span> <span class="kt">string</span> <span class="n">StringClaimValueType</span> <span class="p">=</span> <span class="s">&quot;http://www.w3.org/2001/XMLSchema#string&quot;</span><span class="p">;</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">ClaimsPrincipal</span> <span class="nf">ValidateToken</span><span class="p">(</span><span class="kt">string</span> <span class="n">token</span><span class="p">,</span> <span class="n">X509Certificate2</span> <span class="n">certificate</span><span class="p">,</span> <span class="kt">string</span> <span class="n">audience</span> <span class="p">=</span> <span class="k">null</span><span class="p">,</span> <span class="kt">string</span> <span class="n">issuer</span> <span class="p">=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">claims</span> <span class="p">=</span> <span class="n">ValidateIdentityTokenAsync</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">audience</span><span class="p">,</span> <span class="n">certificate</span><span class="p">);</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">ClaimsPrincipal</span><span class="p">(</span><span class="n">ClaimsIdentityFromJwt</span><span class="p">(</span><span class="n">claims</span><span class="p">,</span> <span class="n">issuer</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">static</span> <span class="n">ClaimsIdentity</span> <span class="nf">ClaimsIdentityFromJwt</span><span class="p">(</span><span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">Claim</span><span class="p">&gt;</span> <span class="n">claims</span><span class="p">,</span> <span class="kt">string</span> <span class="n">issuer</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">subject</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ClaimsIdentity</span><span class="p">(</span><span class="s">&quot;Federation&quot;</span><span class="p">,</span> <span class="n">NameClaimType</span><span class="p">,</span> <span class="n">RoleClaimType</span><span class="p">);</span>
<span class="c1">//var claims = ClaimsFromJwt(jwtData, issuer);</span>
<span class="k">foreach</span> <span class="p">(</span><span class="n">Claim</span> <span class="n">claim</span> <span class="k">in</span> <span class="n">claims</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">type</span> <span class="p">=</span> <span class="n">claim</span><span class="p">.</span><span class="n">Type</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">type</span> <span class="p">==</span> <span class="n">ActorClaimType</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">subject</span><span class="p">.</span><span class="n">Actor</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">InvalidOperationException</span><span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="n">Format</span><span class="p">(</span>
<span class="s">&quot;Jwt10401: Only a single &#39;Actor&#39; is supported. Found second claim of type: &#39;{0}&#39;, value: &#39;{1}&#39;&quot;</span><span class="p">,</span> <span class="k">new</span> <span class="kt">object</span><span class="p">[]</span> <span class="p">{</span> <span class="s">&quot;actor&quot;</span><span class="p">,</span> <span class="n">claim</span><span class="p">.</span><span class="n">Value</span> <span class="p">}));</span>
<span class="p">}</span>
<span class="n">subject</span><span class="p">.</span><span class="n">AddClaim</span><span class="p">(</span><span class="k">new</span> <span class="n">Claim</span><span class="p">(</span><span class="n">type</span><span class="p">,</span> <span class="n">claim</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="n">claim</span><span class="p">.</span><span class="n">ValueType</span><span class="p">,</span> <span class="n">issuer</span><span class="p">,</span> <span class="n">issuer</span><span class="p">,</span> <span class="n">subject</span><span class="p">));</span>
<span class="k">continue</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">type</span> <span class="p">==</span> <span class="s">&quot;name&quot;</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">subject</span><span class="p">.</span><span class="n">AddClaim</span><span class="p">(</span><span class="k">new</span> <span class="n">Claim</span><span class="p">(</span><span class="n">NameClaimType</span><span class="p">,</span> <span class="n">claim</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="n">StringClaimValueType</span><span class="p">,</span> <span class="n">issuer</span><span class="p">,</span> <span class="n">issuer</span><span class="p">));</span>
<span class="k">continue</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">type</span> <span class="p">==</span> <span class="s">&quot;role&quot;</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">subject</span><span class="p">.</span><span class="n">AddClaim</span><span class="p">(</span><span class="k">new</span> <span class="n">Claim</span><span class="p">(</span><span class="n">RoleClaimType</span><span class="p">,</span> <span class="n">claim</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="n">StringClaimValueType</span><span class="p">,</span> <span class="n">issuer</span><span class="p">,</span> <span class="n">issuer</span><span class="p">));</span>
<span class="k">continue</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">var</span> <span class="n">newClaim</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Claim</span><span class="p">(</span><span class="n">type</span><span class="p">,</span> <span class="n">claim</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="n">claim</span><span class="p">.</span><span class="n">ValueType</span><span class="p">,</span> <span class="n">issuer</span><span class="p">,</span> <span class="n">issuer</span><span class="p">,</span> <span class="n">subject</span><span class="p">);</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">prop</span> <span class="k">in</span> <span class="n">claim</span><span class="p">.</span><span class="n">Properties</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">newClaim</span><span class="p">.</span><span class="n">Properties</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="n">prop</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">subject</span><span class="p">.</span><span class="n">AddClaim</span><span class="p">(</span><span class="n">newClaim</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">subject</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">static</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">Claim</span><span class="p">&gt;</span> <span class="n">ValidateIdentityTokenAsync</span><span class="p">(</span><span class="kt">string</span> <span class="n">token</span><span class="p">,</span> <span class="kt">string</span> <span class="n">audience</span><span class="p">,</span> <span class="n">X509Certificate2</span> <span class="n">certificate</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">parameters</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TokenValidationParameters</span>
<span class="p">{</span>
<span class="n">ValidAudience</span> <span class="p">=</span> <span class="n">audience</span><span class="p">,</span>
<span class="n">ValidIssuer</span> <span class="p">=</span> <span class="s">&quot;http://localhost:22530&quot;</span><span class="p">,</span>
<span class="n">IssuerSigningToken</span> <span class="p">=</span> <span class="k">new</span> <span class="n">X509SecurityToken</span><span class="p">(</span><span class="n">certificate</span><span class="p">)</span>
<span class="p">};</span>
<span class="kt">var</span> <span class="n">handler</span> <span class="p">=</span> <span class="k">new</span> <span class="n">JwtSecurityTokenHandler</span><span class="p">();</span>
<span class="n">SecurityToken</span> <span class="n">jwt</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">id</span> <span class="p">=</span> <span class="n">handler</span><span class="p">.</span><span class="n">ValidateToken</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">parameters</span><span class="p">,</span> <span class="k">out</span> <span class="n">jwt</span><span class="p">);</span>
<span class="k">return</span> <span class="n">id</span><span class="p">.</span><span class="n">Claims</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</p>
<p>At this point we can use a tool like postman to send authenticated requests to service stack and out provider will correctly authorize the user. While we are targetting access_tokens you can also validate the id_token if you pass that in instead, although that wouldn&rsquo;t really make a lot of sense unless all you are trying to do is authenticate the user.</p>
<h1 id="step-3-angular:0c891f9681739990127d39f58407d9b9">Step 3 Angular</h1>
<p>For angular we will use the OidcTokenManager library to handle the authentications flows. All we need to do is hook the library up in a few places and ensure that we are passing the token on all calls to the server.</p>
<p>First we configure OidcTokenManager:</p>
<p><div class="highlight"><pre> <span class="nx">angular</span>
<span class="p">.</span><span class="nx">module</span><span class="p">(</span><span class="s1">&#39;app.core&#39;</span><span class="p">)</span>
<span class="p">.</span><span class="nx">factory</span><span class="p">(</span><span class="s1">&#39;authService&#39;</span><span class="p">,</span> <span class="nx">authService</span><span class="p">);</span>
<span class="cm">/* @ngInject */</span>
<span class="kd">function</span> <span class="nx">authService</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">config</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">authority</span><span class="o">:</span> <span class="s2">&quot;http://localhost:22530/&quot;</span><span class="p">,</span>
<span class="nx">client_id</span><span class="o">:</span> <span class="s2">&quot;js_oidc&quot;</span><span class="p">,</span>
<span class="nx">redirect_uri</span><span class="o">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">protocol</span> <span class="o">+</span> <span class="s2">&quot;//&quot;</span> <span class="o">+</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">host</span> <span class="o">+</span> <span class="s2">&quot;/callback.html&quot;</span><span class="p">,</span>
<span class="nx">post_logout_redirect_uri</span><span class="o">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">protocol</span> <span class="o">+</span> <span class="s2">&quot;//&quot;</span> <span class="o">+</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">host</span> <span class="o">+</span> <span class="s2">&quot;/index.html&quot;</span><span class="p">,</span>
<span class="c1">// these two will be done dynamically from the buttons clicked, but are</span>
<span class="c1">// needed if you want to use the silent_renew</span>
<span class="nx">response_type</span><span class="o">:</span> <span class="s2">&quot;id_token token&quot;</span><span class="p">,</span>
<span class="nx">scope</span><span class="o">:</span> <span class="s2">&quot;openid profile email api1 api2&quot;</span><span class="p">,</span>
<span class="c1">// this will toggle if profile endpoint is used</span>
<span class="nx">load_user_profile</span><span class="o">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="c1">// silent renew will get a new access_token via an iframe </span>
<span class="c1">// just prior to the old access_token expiring (60 seconds prior)</span>
<span class="nx">silent_redirect_uri</span><span class="o">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">protocol</span> <span class="o">+</span> <span class="s2">&quot;//&quot;</span> <span class="o">+</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">host</span> <span class="o">+</span> <span class="s2">&quot;/silent_renew.html&quot;</span><span class="p">,</span>
<span class="nx">silent_renew</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="c1">// this will allow all the OIDC protocol claims to be visible in the window. normally a client app </span>
<span class="c1">// wouldn&#39;t care about them or want them taking up space</span>
<span class="nx">filter_protocol_claims</span><span class="o">:</span> <span class="kc">false</span>
<span class="p">};</span>
<span class="kd">var</span> <span class="nx">mgr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OidcTokenManager</span><span class="p">(</span><span class="nx">config</span><span class="p">);</span>
<span class="k">return</span> <span class="p">{</span> <span class="nx">OidcTokenManager</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">mgr</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</p>
<p>Then we create the page that will handle the call back from identity server it will store the token in localStorage.</p>
<p><div class="highlight"><pre>
<span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;head&gt;</span>
<span class="nt">&lt;title&gt;&lt;/title&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">&quot;utf-8&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
<span class="nt">&lt;script </span><span class="na">src=</span><span class="s">&quot;/bower_components/oidc-token-manager/dist/oidc-token-manager.js&quot;</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script&gt;</span>
<span class="kd">var</span> <span class="nx">config</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">authority</span><span class="o">:</span> <span class="s2">&quot;http://localhost:22530/&quot;</span><span class="p">,</span>
<span class="nx">client_id</span><span class="o">:</span> <span class="s2">&quot;js_oidc&quot;</span><span class="p">,</span>
<span class="nx">redirect_uri</span><span class="o">:</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">protocol</span> <span class="o">+</span> <span class="s2">&quot;//&quot;</span> <span class="o">+</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">host</span> <span class="o">+</span> <span class="s2">&quot;/index.html&quot;</span>
<span class="p">};</span>
<span class="kd">var</span> <span class="nx">mgr</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">OidcTokenManager</span><span class="p">(</span><span class="nx">config</span><span class="p">);</span>
<span class="nx">mgr</span><span class="p">.</span><span class="nx">processTokenCallbackAsync</span><span class="p">().</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">location</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">protocol</span> <span class="o">+</span> <span class="s2">&quot;//&quot;</span> <span class="o">+</span> <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">host</span><span class="p">;</span>
<span class="p">},</span>
<span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">alert</span><span class="p">(</span><span class="s2">&quot;There was a problem getting the Token: &quot;</span> <span class="o">+</span> <span class="p">(</span><span class="nx">error</span><span class="p">.</span><span class="nx">message</span> <span class="o">||</span> <span class="nx">error</span><span class="p">));</span>
<span class="p">});</span>
<span class="nt">&lt;/script&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</pre></div>
</p>
<p>Finally we need to make sure that any calls sent to the server have the token added as a authentication header.
<div class="highlight"><pre> <span class="nx">angular</span>
<span class="p">.</span><span class="nx">module</span><span class="p">(</span><span class="s1">&#39;app.core&#39;</span><span class="p">)</span>
<span class="p">.</span><span class="nx">factory</span><span class="p">(</span><span class="s1">&#39;oidcInterceptor&#39;</span><span class="p">,</span> <span class="nx">oidcInterceptor</span><span class="p">);</span>
<span class="cm">/* @ngInject */</span>
<span class="kd">function</span> <span class="nx">oidcInterceptor</span><span class="p">(</span><span class="nx">globalConfig</span><span class="p">,</span> <span class="nx">authService</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span>
<span class="s1">&#39;request&#39;</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">config</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">config</span><span class="p">.</span><span class="nx">url</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">globalConfig</span><span class="p">.</span><span class="nx">baseUrl</span><span class="p">)</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">config</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">Authorization</span> <span class="o">=</span> <span class="s1">&#39;Bearer &#39;</span> <span class="o">+</span> <span class="nx">authService</span><span class="p">.</span><span class="nx">OidcTokenManager</span><span class="p">().</span><span class="nx">access_token</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">config</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</p>
<p>The full code is available on <a href="https://github.com/Estyn/ServiceStackJWT">github</a>.</p>
</description>
</item>
<item>
<title>Using a JQuery Plugin in Angular 2</title>
<link>http://estynedwards.com/blog/2015/12/04/getting%20started%20with%20angular%202/</link>
<pubDate>Fri, 04 Dec 2015 00:00:00 +0000</pubDate>
<guid>http://estynedwards.com/blog/2015/12/04/getting%20started%20with%20angular%202/</guid>
<description><p>I have been working on a small content editing tool for an internal project and decided to try using angular 2. For this project I want to use the TinyMCE.js. In anglar 1.x I would wrap it in a directive and work with it that way.</p>
<aside class="notice">
This code was testing with alpha 48
</aside>
<p>In angular 2.0 there are no directives, instead we use a component which ends up being much simpler than a directive. The full code is below folled by a brief explaination.</p>
<p><div class="highlight"><pre><span class="kr">import</span> <span class="p">{</span><span class="nx">Component</span><span class="p">,</span> <span class="nx">View</span><span class="p">,</span> <span class="nx">ElementRef</span><span class="p">,</span> <span class="nx">OnInit</span><span class="p">,</span> <span class="nx">Input</span><span class="p">,</span> <span class="nx">Output</span><span class="p">,</span> <span class="nx">EventEmitter</span><span class="p">,</span><span class="nx">OnChanges</span><span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;angular2/angular2&#39;</span><span class="p">;</span>
<span class="kr">declare</span> <span class="kd">var</span> <span class="nx">tinymce</span>: <span class="kt">any</span><span class="p">;</span>
<span class="err">@</span><span class="nx">Component</span><span class="p">({</span>
<span class="nx">selector</span><span class="o">:</span> <span class="s1">&#39;tiny-editor&#39;</span><span class="p">,</span>
<span class="p">})</span>
<span class="err">@</span><span class="nx">View</span><span class="p">({</span>
<span class="nx">template</span><span class="o">:</span> <span class="err">`</span><span class="o">&lt;</span><span class="nx">textarea</span> <span class="kr">class</span><span class="o">=</span><span class="s2">&quot;tinyMCE&quot;</span> <span class="nx">style</span><span class="o">=</span><span class="s2">&quot;height:300px&quot;</span><span class="o">&gt;&lt;</span><span class="err">/textarea&gt;`</span>
<span class="p">})</span>
<span class="kr">export</span> <span class="kr">class</span> <span class="nx">TinyEditor</span> <span class="kr">implements</span> <span class="nx">OnInit</span> <span class="p">{</span>
<span class="err">@</span><span class="nx">Input</span><span class="p">()</span> <span class="nx">value</span>: <span class="kt">any</span><span class="p">;</span>
<span class="err">@</span><span class="nx">Output</span><span class="p">()</span> <span class="nx">valueChange</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">EventEmitter</span><span class="p">();</span>
<span class="nx">elementRef</span>: <span class="kt">ElementRef</span><span class="p">;</span>
<span class="kr">constructor</span><span class="p">(</span><span class="nx">elementRef</span>: <span class="kt">ElementRef</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">elementRef</span> <span class="o">=</span> <span class="nx">elementRef</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">onInit() {</span>
<span class="kd">var</span> <span class="nx">that</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
<span class="nx">tinymce</span><span class="p">.</span><span class="nx">init</span><span class="p">(</span>
<span class="p">{</span>
<span class="nx">selector</span><span class="o">:</span> <span class="s2">&quot;.tinyMCE&quot;</span><span class="p">,</span>
<span class="nx">plugins</span><span class="o">:</span> <span class="p">[</span><span class="s2">&quot;code&quot;</span><span class="p">],</span>
<span class="nx">menubar</span>: <span class="kt">false</span><span class="p">,</span>
<span class="nx">toolbar1</span><span class="o">:</span> <span class="s2">&quot;bold italic underline strikethrough alignleft aligncenter alignright alignjustify styleselect bullist numlist outdent indent blockquote undo redo removeformat subscript superscript | code&quot;</span><span class="p">,</span>
<span class="nx">setup</span><span class="o">:</span> <span class="p">(</span><span class="nx">editor</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
<span class="nx">editor</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;change&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">e</span><span class="p">,</span> <span class="nx">l</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
<span class="nx">that</span><span class="p">.</span><span class="nx">valueChange</span><span class="p">.</span><span class="nx">next</span><span class="p">(</span><span class="nx">editor</span><span class="p">.</span><span class="nx">getContent</span><span class="p">());</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="nx">onChanges</span><span class="p">(</span><span class="nx">changes</span><span class="p">){</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">tinymce</span><span class="p">.</span><span class="nx">activeEditor</span><span class="p">)</span>
<span class="nx">tinymce</span><span class="p">.</span><span class="nx">activeEditor</span><span class="p">.</span><span class="nx">setContent</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
With the tinyMCE component we want to have two way binding for the text in the editor. In order to do this we need to use Input (with OnChanges) and Output (with EventEmmiter).</p>
<p>Usage:
<div class="highlight"><pre><span class="nt">&lt;tiny-editor</span> <span class="err">[</span><span class="na">value</span><span class="err">]=&quot;</span><span class="na">model</span><span class="err">.</span><span class="na">data</span><span class="err">&quot;</span> <span class="err">(</span><span class="na">value-change</span><span class="err">)=&quot;</span><span class="na">model</span><span class="err">.</span><span class="na">data=</span><span class="s">$event&quot;</span><span class="nt">&gt;&lt;/tiny-editor&gt;</span>
</pre></div>
In order to make sure that the editor updates when the text changes we implement the onChanges event which will fire everytime any of the inputs changes. In this case we only have one input so we can update the editor everytime there is a change.</p>
<p>Updating the model when there is a change in the editor is a little bit more complicated, in order to do this we use an event emmitter. We setup tinyMCE&rsquo;s change event to call &lsquo;next&rsquo; on our event emitter to allow us bind the new data back to the model.</p>
</description>
</item>
<item>
<title>Using Geny Motion for Xamarin Android Development in a VM</title>
<link>http://estynedwards.com/blog/2014/01/15/using-geny-motion-for-xamarin-android-development-in-a-vm/</link>
<pubDate>Wed, 15 Jan 2014 00:00:00 +0000</pubDate>
<guid>http://estynedwards.com/blog/2014/01/15/using-geny-motion-for-xamarin-android-development-in-a-vm/</guid>
<description><p>I&rsquo;ve been doing a fair bit of android development using the Xamarin to allow me to code in c#. I personally like to do all of my development in a virtual machine which allows me to have separate environments for different project. This works well for most development, but for mobile development it posses some challenges when trying to run emulators.</p>
<p>I had been using VMWare to virtualize my development and a nexus 4 for testing. I was also using the android emulators, but as most android developers know they run very slow. I hear about <a href="http://www.genymotion.com/">Genymotion</a> which is a super face android emulator. It uses <a href="http://www.virtualbox.org/">VirtualBox</a> to host the android vm, unfortunately VirtualBox <a href="http://www.virtualbox.org/manual/ch10.html#hwvirt">does not recomend</a> running VirtualBox and VMWare at the same time. Luckily moving the VMWare VM to VirtualBox is as simple as opening the VM with VirtualBox, no conversion needed.</p>
<p>Getting Genymotion working is fairly simple. Follow the regular instructions to install Genymotion, once it installed we need to configure debugging on the development VM to point to the Genymotion VM.</p>
<p>First start you Genymotion machine, and open the Genymotion Configuration app to determine the IP address of the emulator. In my case it was 192.168.56.101.</p>
<p>Now in the development machine you will need to run adb.exe (C:\Users\Administrator\AppData\Local\Android\android-sdk\platform-tools\adb.exe) from the command prompt.</p>
<pre><code> .\adb.exe connect 192.168.56.101
</code></pre>
<p>You should see connected to 192.168.56.101 if everything worked correctly. If you don&rsquo;t see that you will need to check your networking setting on you VM and on Genymotion. In my case I configured both as NAT.</p>
<p>If you have both machines configured as NAT and you want to be able to access a service hosted on your dev machine from either your host of the emulator you will need to configure your development VM network&rsquo;s port forwarding. Figure out your dev vm&rsquo;s ip address (10.0.2.15 in my case) then create your port forwarding rule.</p>
<ul>
<li>Name: MyRule</li>
<li>Protocol: TCP</li>
<li>HostIP: 127.0.0.1</li>
<li>Host Port: 88</li>
<li>Guest IP 10.0.2.15</li>
<li>Guest Port: 88</li>
</ul>
<p>Now you should be setup for development in your VM with a nice fast emulater running on your host.</p>
</description>
</item>
<item>
<title>Better Logging in Azure Mobile Services</title>
<link>http://estynedwards.com/blog/2013/12/12/better-logging-in-azure-mobile-services/</link>
<pubDate>Thu, 12 Dec 2013 00:00:00 +0000</pubDate>
<guid>http://estynedwards.com/blog/2013/12/12/better-logging-in-azure-mobile-services/</guid>
<description>
<p>Debugging in azure mobile services can be frustrating, it only runs on Azure servers and you can&rsquo;t run any debugging tools on it. Logging is pretty much the only way to debug your services. The default logging using console.log is fairly limited. You can&rsquo;t turn it on or off easily or change the logging level. It also doesn&rsquo;t include the line number which can make it harder to debug a large service.</p>
<h2 id="installing-tracer:2f39450fed439462d39e03c2283dd003">Installing Tracer</h2>
<p>Fortunately there are some excellent node modules for logging that work fairly well with Azure Mobile Services. I&rsquo;m using the excellent <a href="https://github.com/baryon/tracer">tracer</a> module.</p>
<p>Installing the module is fairly straight forward, you will first need to <a href="http://www.windowsazure.com/en-us/develop/mobile/tutorials/store-scripts-in-source-control/">setup git access</a>. You then need to install the trace module.
<div class="highlight"><pre> <span class="nx">npm</span> <span class="nx">install</span> <span class="nx">tracer</span>
</pre></div>
Once you have the the module installed you can use it in your scripts.
<div class="highlight"><pre> <span class="kd">var</span> <span class="nx">logger</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;tracer&#39;</span><span class="p">).</span><span class="nx">console</span><span class="p">();</span>
<span class="nx">logger</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;hello&#39;</span><span class="p">);</span>
<span class="nx">logger</span><span class="p">.</span><span class="nx">trace</span><span class="p">(</span><span class="s1">&#39;hello&#39;</span><span class="p">,</span> <span class="s1">&#39;world&#39;</span><span class="p">);</span>
<span class="nx">logger</span><span class="p">.</span><span class="nx">debug</span><span class="p">(</span><span class="s1">&#39;hello %s&#39;</span><span class="p">,</span> <span class="s1">&#39;world&#39;</span><span class="p">,</span> <span class="mi">123</span><span class="p">);</span>
<span class="nx">logger</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s1">&#39;hello %s %d&#39;</span><span class="p">,</span> <span class="s1">&#39;world&#39;</span><span class="p">,</span> <span class="mi">123</span><span class="p">,</span> <span class="p">{</span><span class="nx">foo</span><span class="o">:</span><span class="s1">&#39;bar&#39;</span><span class="p">});</span>
<span class="nx">logger</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="s1">&#39;hello %s %d %j&#39;</span><span class="p">,</span> <span class="s1">&#39;world&#39;</span><span class="p">,</span> <span class="mi">123</span><span class="p">,</span> <span class="p">{</span><span class="nx">foo</span><span class="o">:</span><span class="s1">&#39;bar&#39;</span><span class="p">});</span>
<span class="nx">logger</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s1">&#39;hello %s %d %j&#39;</span><span class="p">,</span> <span class="s1">&#39;world&#39;</span><span class="p">,</span> <span class="mi">123</span><span class="p">,</span> <span class="p">{</span><span class="nx">foo</span><span class="o">:</span><span class="s1">&#39;bar&#39;</span><span class="p">},</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">],</span> <span class="nb">Object</span><span class="p">);</span>
</pre></div>
When you use the the logger it will include the line number as well as the logging level.</p>
<h2 id="setting-the-logging-level:2f39450fed439462d39e03c2283dd003">Setting the Logging Level</h2>
<p>You can set the logging level fairly simply:
<div class="highlight"><pre> <span class="kd">var</span> <span class="nx">logger</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;tracer&#39;</span><span class="p">).</span><span class="nx">colorConsole</span><span class="p">({</span><span class="nx">level</span><span class="o">:</span><span class="s1">&#39;warn&#39;</span><span class="p">});</span>
</pre></div>
An even better way to do it is to use an app setting to set the logging level. That way you can use azure portal to set the logging level without having to change any of the scripts.
<div class="highlight"><pre> <span class="kd">var</span> <span class="nx">logger</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;tracer&#39;</span><span class="p">).</span><span class="nx">colorConsole</span><span class="p">({</span><span class="nx">level</span><span class="o">:</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">LoggerLevel</span><span class="p">});</span>
</pre></div>
</p>
<h2 id="using-colour-and-log-watcher:2f39450fed439462d39e03c2283dd003">Using Colour and Log Watcher</h2>
<p>The web view of the logs isn&rsquo;t very useful for logging, instead I use a <a href="http://www.thejoyofcode.com/A_Mobile_Services_Log_Watcher_Day_6_.aspx">node.js script</a> from Josh Twist that polls the logs from the api. This allows you to see the errors as they happened and stops you from having to refresh a web page manually.</p>
<p>As an additional bonus you can use colours when you are using the script. This makes it much easier to keep things organized.
<div class="highlight"><pre> <span class="kd">var</span> <span class="nx">_</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;lodash&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">colors</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;colors&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">logger</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;tracer&#39;</span><span class="p">).</span><span class="nx">colorConsole</span><span class="p">({</span><span class="nx">filters</span> <span class="o">:</span> <span class="p">{</span>
<span class="nx">log</span> <span class="o">:</span> <span class="nx">colors</span><span class="p">.</span><span class="nx">white</span><span class="p">,</span>
<span class="nx">trace</span> <span class="o">:</span> <span class="nx">colors</span><span class="p">.</span><span class="nx">grey</span><span class="p">,</span>
<span class="nx">debug</span> <span class="o">:</span> <span class="nx">colors</span><span class="p">.</span><span class="nx">magenta</span><span class="p">,</span>
<span class="nx">info</span> <span class="o">:</span> <span class="nx">colors</span><span class="p">.</span><span class="nx">green</span><span class="p">,</span>
<span class="nx">warn</span> <span class="o">:</span> <span class="nx">colors</span><span class="p">.</span><span class="nx">yellow</span><span class="p">,</span>
<span class="nx">error</span> <span class="o">:</span> <span class="p">[</span> <span class="nx">colors</span><span class="p">.</span><span class="nx">red</span><span class="p">,</span> <span class="nx">colors</span><span class="p">.</span><span class="nx">bold</span> <span class="p">]</span>
<span class="p">},</span>
<span class="nx">level</span><span class="o">:</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">LoggerLevel</span> <span class="c1">//log,trace,debug,info,warn,error</span>
<span class="p">});</span>
</pre></div>
</p>
</description>
</item>
<item>
<title>Azure Dev Machine Auto Shutdown Part 2</title>
<link>http://estynedwards.com/blog/2013/09/06/azure-dev-machine-auto-shutdown-part-2/</link>
<pubDate>Fri, 06 Sep 2013 00:00:00 +0000</pubDate>
<guid>http://estynedwards.com/blog/2013/09/06/azure-dev-machine-auto-shutdown-part-2/</guid>
<description>
<p>In <a href="http://estynedwards.com/blog/2013/09/03/auto-shutdown-for-windows-azure-vm/">Part 1</a> we looked at how to set-up a simple script to shut down an azure virtual machine after a period of inactivity. The problem I had with the previous solution was determining the amount of inactivity time to set the script to run at. I often found the machine was shutting down when I didn&rsquo;t want it to. In this post we will add SMS notification when the machine is about to shut down and we will add an option for cancelling the shut down.
&lt;!&ndash; more &ndash;&gt;</p>
<h2 id="step-1-get-a-twillio-https-www-twilio-com-user-account-account-if-you-don-t-already-have-one:0716029e4afe5b7c2e2968be46ffbacd">Step 1: Get a <a href="https://www.twilio.com/user/account">Twillio</a> account if you don&rsquo;t already have one.</h2>
<p>Twillio has a free trial account that will allow you to send free SMS&rsquo;s to your own phone. Once you have a Twillio account you will need to write down your Account SID and you Auth Token, both can be found on the main account page in Twillio. You will also need to write down your Twillio phone number.</p>
<h2 id="step-2-get-the-twillio-and-restsharp-dll:0716029e4afe5b7c2e2968be46ffbacd">Step 2: Get the Twillio and RestSharp dll</h2>
<p>In order to use Twillio from powershell we will need to have a copy of Twillio.API.dll which has a dependency on RestSharp.dll so we will need that as well. I&rsquo;ve found NuGet to be the easiest way to get both.
<div class="highlight"><pre><span class="n">Install-Package</span> <span class="n">Twilio</span>
</pre></div>
<div class="highlight"><pre><span class="n">Install-Package</span> <span class="n">RestSharp</span><span class="p">`</span>
</pre></div>
</p>
<p>Once you have the dlls save them in the same folder as your script.</p>
<h2 id="step-3-modify-the-script-to-send-an-sms-prior-to-shutting-down:0716029e4afe5b7c2e2968be46ffbacd">Step 3: Modify the script to send an SMS prior to shutting down</h2>
<p><div class="highlight"><pre><span class="nb">Add-Type</span> <span class="n">-path</span> <span class="s2">&quot;c:\Twilio.Api.dll&quot;</span>
<span class="nb">Add-Type</span> <span class="n">-path</span> <span class="s2">&quot;c:\RestSharp.dll&quot;</span>
<span class="nv">$twilio</span> <span class="p">=</span> <span class="nb">new-object</span> <span class="n">Twilio</span><span class="p">.</span><span class="n">TwilioRestClient</span><span class="p">(</span><span class="s2">&quot;YOURACCOUNTSID&quot;</span><span class="p">,</span> <span class="s2">&quot;YOURAUTHTOKEN&quot;</span><span class="p">)</span>
<span class="nv">$msg</span> <span class="p">=</span> <span class="nv">$twilio</span><span class="p">.</span><span class="n">SendSmsMessage</span><span class="p">(</span><span class="s2">&quot;YOURTWILLIONUMBER&quot;</span><span class="p">,</span> <span class="s2">&quot;YOURCELLPHONENUMBER&quot;</span><span class="p">,</span> <span class="s2">&quot;VM about to shutdown&quot;</span><span class="p">)</span>
</pre></div>
</p>
<h2 id="step-4-add-a-delay-to-the-script:0716029e4afe5b7c2e2968be46ffbacd">Step 4: Add a delay to the script</h2>
<p>Having a notification that the VM is about to shut down isn&rsquo;t very useful if you can&rsquo;t do anything about it so we will add a delay so that you can cancel the shut down after having received the notification.</p>
<p>I&rsquo;m using a nice script by <a href="http://jdhitsolutions.com/blog/2012/04/friday-fun-powershell-countdown/">Jeffery Hicks</a> that displays a nice countdown message on the screen before executing the shut down. You can read his blog post to see how the script works. The complete script is listed below, it sends an SMS then waits 15 minutes before executing the shut down command. The countdown can be interrupted with the esc key to prevent the shut down.</p>
<p><div class="highlight"><pre><span class="cm">&lt;#</span>
<span class="cm"> -----------------------------------------------------------------------------</span>
<span class="cm"> Script: Countdown2.ps1</span>
<span class="cm"> Version: 0.9</span>
<span class="cm"> Author: Jeffery Hicks</span>
<span class="cm"> http://jdhitsolutions.com/blog</span>
<span class="cm"> http://twitter.com/JeffHicks</span>
<span class="cm"> http://www.ScriptingGeek.com</span>
<span class="cm"> Date: 4/27/2012</span>
<span class="cm"> Keywords:</span>
<span class="cm"> Comments:</span>
<span class="cm"> This is a variation on the Start-Countdown script from Josh Atwell</span>
<span class="cm"> (http://www.vtesseract.com/post/21414227113/start-countdown-function-a-visual-for-start-sleep)</span>
<span class="cm"> &quot;Those who forget to script are doomed to repeat their work.&quot;</span>
<span class="cm"> ****************************************************************</span>
<span class="cm"> * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *</span>
<span class="cm"> * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF *</span>
<span class="cm"> * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *</span>
<span class="cm"> * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. *</span>
<span class="cm"> ****************************************************************</span>
<span class="cm"> -----------------------------------------------------------------------------</span>
<span class="cm"> #&gt;</span>
<span class="nb">Import-Module</span> <span class="s2">&quot;C:\Program Files (x86)\Microsoft SDKs\Windows Azure\PowerShell\Azure\Azure.psd1&quot;</span>
<span class="k">Function</span> <span class="nb">Start-Countdown</span> <span class="p">{</span>
<span class="cm">&lt;#</span>
<span class="cm"> </span><span class="sd">.Synopsis</span><span class="cm"></span>
<span class="cm"> Initiates a countdown before running a command</span>
<span class="cm"> </span>
<span class="cm"> </span><span class="sd">.Description</span><span class="cm"> </span>
<span class="cm"> This is a variation on the Start-Countdown script from Josh Atwell</span>
<span class="cm"> (http://www.vtesseract.com/post/21414227113/start-countdown-function-a-visual-for-start-sleep). </span>
<span class="cm"> It can be used instead of Start-Sleep and provides a visual countdown </span>
<span class="cm"> progress during &quot;sleep&quot; times. At the end of the countdown, your </span>
<span class="cm"> command will execute. Press the ESC key any time during the countdown</span>
<span class="cm"> to abort. </span>
<span class="cm"> </span>
<span class="cm"> USING START-COUNTDOWN IN THE POWERSHELL ISE</span>
<span class="cm"> Results will vary slightly in the PowerShell ISE. If you use this in</span>
<span class="cm"> the ISE, it is recommended to use -Clear. You also cannot use the ESC</span>
<span class="cm"> key to abort the script if using the console. You&#39;ll need to press</span>
<span class="cm"> Ctrl+C. If using the progress bar, there is a Stop button in the ISE.</span>
<span class="cm"> If you abort in the ISE, you won&#39;t get the warning message.</span>
<span class="cm"> </span>
<span class="cm"> </span><span class="sd">.Parameter</span><span class="cm"> Seconds</span>
<span class="cm"> The number of seconds to countdown. The default is 10.</span>
<span class="cm"> </span>
<span class="cm"> </span><span class="sd">.Parameter</span><span class="cm"> Scriptblock</span>
<span class="cm"> A PowerShell scriptblock to execute at the end of the countdown.</span>
<span class="cm"> </span>
<span class="cm"> </span><span class="sd">.Parameter</span><span class="cm"> ProgressBar</span>
<span class="cm"> Use a progress bar instead of the console.</span>
<span class="cm"> </span>
<span class="cm"> </span><span class="sd">.Parameter</span><span class="cm"> Clear</span>
<span class="cm"> Clear the screen. Other wise, the countdown will use the current location.</span>
<span class="cm"> </span>
<span class="cm"> </span><span class="sd">.Parameter</span><span class="cm"> Message</span>
<span class="cm"> The message to be displayed at the end of the countdown before any</span>
<span class="cm"> scriptblock is executed.</span>
<span class="cm"> </span>
<span class="cm"> </span><span class="sd">.Example</span><span class="cm"></span>
<span class="cm"> PS C:\&gt; Start-Countdown -Seconds 10 -clear</span>
<span class="cm"> </span>
<span class="cm"> This method will clear the screen and display descending seconds</span>
<span class="cm"> </span>
<span class="cm"> </span><span class="sd">.Example</span><span class="cm"></span>
<span class="cm"> PS C:\&gt; Start-Countdown -Seconds 30 -ProgressBar -scriptblock {get-service -comp (get-content computers.txt)}</span>
<span class="cm"> </span>
<span class="cm"> This method will display a progress bar on screen. At the end of the countdown the scriptblock will execute.</span>
<span class="cm"> </span>
<span class="cm"> </span><span class="sd">.Link</span><span class="cm"></span>
<span class="cm"> http://jdhitsolutions.com/blog</span>
<span class="cm"> </span>
<span class="cm"> </span><span class="sd">.Link</span><span class="cm"></span>
<span class="cm"> Write-Progress</span>
<span class="cm"> </span>
<span class="cm">#&gt;</span>
<span class="k">Param</span><span class="p">(</span>
<span class="p">[</span><span class="k">Parameter</span><span class="p">(</span><span class="k">Position</span><span class="p">=</span><span class="n">0</span><span class="p">,</span><span class="k">HelpMessage</span><span class="p">=</span><span class="s2">&quot;Enter seconds to countdown from&quot;</span><span class="p">)]</span>
<span class="no">[Int]</span><span class="nv">$Seconds</span> <span class="p">=</span> <span class="n">10</span><span class="p">,</span>
<span class="p">[</span><span class="k">Parameter</span><span class="p">(</span><span class="k">Position</span><span class="p">=</span><span class="n">1</span><span class="p">,</span><span class="k">Mandatory</span><span class="p">=</span><span class="nv">$False</span><span class="p">,</span>
<span class="k">HelpMessage</span><span class="p">=</span><span class="s2">&quot;Enter a scriptblock to execute at the end of the countdown&quot;</span><span class="p">)]</span>
<span class="no">[scriptblock]</span><span class="nv">$Scriptblock</span><span class="p">,</span>
<span class="no">[Switch]</span><span class="nv">$ProgressBar</span><span class="p">,</span>
<span class="no">[Switch]</span><span class="nv">$Clear</span><span class="p">,</span>
<span class="no">[String]</span><span class="nv">$Message</span> <span class="p">=</span> <span class="s2">&quot;Sutting down VM&quot;</span>
<span class="p">)</span>
<span class="c">#save beginning value for total seconds</span>
<span class="nv">$TotalSeconds</span><span class="p">=</span><span class="nv">$Seconds</span>
<span class="c">#get current cursor position</span>
<span class="nv">$Coordinate</span> <span class="p">=</span> <span class="nb">New-Object</span> <span class="n">System</span><span class="p">.</span><span class="n">Management</span><span class="p">.</span><span class="n">Automation</span><span class="p">.</span><span class="n">Host</span><span class="p">.</span><span class="n">Coordinates</span>
<span class="nv">$Coordinate</span><span class="p">.</span><span class="n">X</span><span class="p">=</span><span class="nv">$host</span><span class="p">.</span><span class="n">ui</span><span class="p">.</span><span class="n">rawui</span><span class="p">.</span><span class="n">CursorPosition</span><span class="p">.</span><span class="n">X</span>
<span class="nv">$Coordinate</span><span class="p">.</span><span class="n">Y</span><span class="p">=</span><span class="nv">$host</span><span class="p">.</span><span class="n">ui</span><span class="p">.</span><span class="n">rawui</span><span class="p">.</span><span class="n">CursorPosition</span><span class="p">.</span><span class="n">Y</span>
<span class="k">If</span> <span class="p">(</span><span class="nv">$clear</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">Clear-Host</span>
<span class="c">#find the middle of the current window</span>
<span class="nv">$Coordinate</span><span class="p">.</span><span class="n">X</span><span class="p">=</span><span class="no">[int]</span><span class="p">(</span><span class="nv">$host</span><span class="p">.</span><span class="n">ui</span><span class="p">.</span><span class="n">rawui</span><span class="p">.</span><span class="n">WindowSize</span><span class="p">.</span><span class="n">Width</span><span class="p">/</span><span class="n">2</span><span class="p">)</span>
<span class="nv">$Coordinate</span><span class="p">.</span><span class="n">Y</span><span class="p">=</span><span class="no">[int]</span><span class="p">(</span><span class="nv">$host</span><span class="p">.</span><span class="n">ui</span><span class="p">.</span><span class="n">rawui</span><span class="p">.</span><span class="n">WindowSize</span><span class="p">.</span><span class="n">Height</span><span class="p">/</span><span class="n">2</span><span class="p">)</span>
<span class="p">}</span>
<span class="c">#define the Escape key</span>
<span class="nv">$ESCKey</span> <span class="p">=</span> <span class="n">27</span>
<span class="c">#define a variable indicating if the user aborted the countdown</span>
<span class="nv">$Abort</span><span class="p">=</span><span class="nv">$False</span>
<span class="k">while</span> <span class="p">(</span><span class="nv">$seconds</span> <span class="o">-ge</span> <span class="n">1</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$host</span><span class="p">.</span><span class="n">ui</span><span class="p">.</span><span class="n">RawUi</span><span class="p">.</span><span class="n">KeyAvailable</span><span class="p">)</span>
<span class="p">{</span>
<span class="nv">$key</span> <span class="p">=</span> <span class="nv">$host</span><span class="p">.</span><span class="n">ui</span><span class="p">.</span><span class="n">RawUI</span><span class="p">.</span><span class="n">ReadKey</span><span class="p">(</span><span class="s2">&quot;NoEcho,IncludeKeyUp,IncludeKeyDown&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$key</span><span class="p">.</span><span class="n">VirtualKeyCode</span> <span class="o">-eq</span> <span class="nv">$ESCkey</span><span class="p">)</span>
<span class="p">{</span>
<span class="c">#ESC was pressed so quit the countdown and set abort flag to True</span>
<span class="nv">$Seconds</span> <span class="p">=</span> <span class="n">0</span>
<span class="nv">$Abort</span><span class="p">=</span><span class="nv">$True</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">If</span><span class="p">(</span><span class="nv">$ProgressBar</span><span class="p">){</span>
<span class="c">#calculate percent time remaining, but in reverse so the progress bar</span>
<span class="c">#moves from left to right</span>
<span class="nv">$percent</span><span class="p">=</span><span class="n">100</span> <span class="p">-</span> <span class="p">(</span><span class="nv">$seconds</span><span class="p">/</span><span class="nv">$TotalSeconds</span><span class="p">)*</span><span class="n">100</span>
<span class="nb">Write-Progress</span> <span class="n">-Activity</span> <span class="s2">&quot;Countdown&quot;</span> <span class="n">-SecondsRemaining</span> <span class="nv">$Seconds</span> <span class="n">-Status</span> <span class="s2">&quot;Shutting doown in (esc to cancel)&quot;</span> <span class="n">-PercentComplete</span> <span class="nv">$percent</span>
<span class="nb">Start-Sleep</span> <span class="n">-Seconds</span> <span class="n">1</span>
<span class="p">}</span> <span class="k">Else</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$Clear</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">Clear-Host</span>
<span class="p">}</span>
<span class="nv">$host</span><span class="p">.</span><span class="n">ui</span><span class="p">.</span><span class="n">rawui</span><span class="p">.</span><span class="n">CursorPosition</span><span class="p">=</span><span class="nv">$Coordinate</span>
<span class="c">#write the seconds with padded trailing spaces to overwrite any extra digits such</span>
<span class="c">#as moving from 10 to 9</span>
<span class="nv">$pad</span><span class="p">=(</span><span class="nv">$TotalSeconds</span> <span class="o">-as</span> <span class="no">[string]</span><span class="p">).</span><span class="n">Length</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$seconds</span> <span class="o">-le</span> <span class="n">10</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$color</span><span class="p">=</span><span class="s2">&quot;Red&quot;</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="nv">$color</span><span class="p">=</span><span class="s2">&quot;Green&quot;</span>
<span class="p">}</span>
<span class="nb">Write-Host</span> <span class="s2">&quot;ESC to cancel: </span><span class="p">$((</span><span class="no">[string]</span><span class="nv">$Seconds</span><span class="p">).</span><span class="n">Padright</span><span class="p">(</span><span class="nv">$pad</span><span class="p">))</span><span class="s2">&quot;</span> <span class="n">-foregroundcolor</span> <span class="nv">$color</span>
<span class="nb">Start-Sleep</span> <span class="n">-Seconds</span> <span class="n">1</span>
<span class="p">}</span>
<span class="c">#decrement $Seconds</span>
<span class="nv">$Seconds</span><span class="p">--</span>
<span class="p">}</span> <span class="c">#while</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$Progress</span><span class="p">)</span> <span class="p">{</span>
<span class="c">#set progress to complete</span>
<span class="nb">Write-Progress</span> <span class="n">-Completed</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="o">-Not</span> <span class="nv">$Abort</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$clear</span><span class="p">)</span> <span class="p">{</span>
<span class="c">#if $Clear was used, center the message in the console</span>
<span class="nv">$Coordinate</span><span class="p">.</span><span class="n">X</span><span class="p">=</span><span class="nv">$Coordinate</span><span class="p">.</span><span class="n">X</span> <span class="p">-</span> <span class="p">(</span><span class="no">[int]</span><span class="p">(</span><span class="nv">$message</span><span class="p">.</span><span class="n">Length</span><span class="p">)/</span><span class="n">2</span><span class="p">)</span>
<span class="p">}</span>
<span class="nv">$host</span><span class="p">.</span><span class="n">ui</span><span class="p">.</span><span class="n">rawui</span><span class="p">.</span><span class="n">CursorPosition</span><span class="p">=</span><span class="nv">$Coordinate</span>
<span class="nb">Write-Host</span> <span class="nv">$Message</span> <span class="n">-ForegroundColor</span> <span class="n">Green</span>
<span class="c">#run the scriptblock if specified</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$scriptblock</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">Invoke-Command</span> <span class="n">-ScriptBlock</span> <span class="nv">$Scriptblock</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="nb">Write-Warning</span> <span class="s2">&quot;Countdown aborted&quot;</span>
<span class="p">}</span>
<span class="p">}</span> <span class="c">#end function</span>
<span class="nv">$sb</span> <span class="p">=</span> <span class="p">{</span><span class="nb">Stop-AzureVM</span> <span class="n">-Name</span> <span class="s2">&quot;YOURVMNAME&quot;</span> <span class="n">-ServiceName</span> <span class="s2">&quot;YOURSERVICENAME&quot;</span> <span class="n">-Force</span><span class="p">}</span>
<span class="nb">Add-Type</span> <span class="n">-path</span> <span class="s2">&quot;c:\Twilio.Api.dll&quot;</span>
<span class="nb">Add-Type</span> <span class="n">-path</span> <span class="s2">&quot;c:\RestSharp.dll&quot;</span>
<span class="nv">$twilio</span> <span class="p">=</span> <span class="nb">new-object</span> <span class="n">Twilio</span><span class="p">.</span><span class="n">TwilioRestClient</span><span class="p">(</span><span class="s2">&quot;YOURACCOUNTSID&quot;</span><span class="p">,</span> <span class="s2">&quot;YOURAUTHTOKEN&quot;</span><span class="p">)</span>
<span class="nv">$msg</span> <span class="p">=</span> <span class="nv">$twilio</span><span class="p">.</span><span class="n">SendSmsMessage</span><span class="p">(</span><span class="s2">&quot;YOURTWILLIONUMBER&quot;</span><span class="p">,</span> <span class="s2">&quot;YOURCELLPHONENUMBER&quot;</span><span class="p">,</span> <span class="s2">&quot;VM about to shutdown&quot;</span><span class="p">)</span>
<span class="nb">Start-Countdown</span> <span class="n">900</span> <span class="n">-Scriptblock</span> <span class="nv">$sb</span> <span class="n">-ProgressBar</span> <span class="n">-Clear</span>
</pre></div>
</p>
</description>
</item>
<item>
<title>Auto Shutdown For Windows Azure VM</title>
<link>http://estynedwards.com/blog/2013/09/03/auto-shutdown-for-windows-azure-vm/</link>
<pubDate>Tue, 03 Sep 2013 00:00:00 +0000</pubDate>
<guid>http://estynedwards.com/blog/2013/09/03/auto-shutdown-for-windows-azure-vm/</guid>
<description>
<p>Thanks to the new MSDN credits that we get with our bizspack membership we have moved all of our development to Azure VMs. Now that stopped (deallocated) VMs don&rsquo;t get charged we are able to have fairly large VMs for our dev machines as long as we remember to turn them off at night. In order to make sure that we don&rsquo;t forget we put together a simple script that will shutdown the VM when called.</p>
<h3 id="update-see-part-2-blog-2013-09-06-azure-dev-machine-auto-shutdown-part-2-for-adding-sms-notification-and-cancellation:e2fbb72c5252ed814adc8984c782fa02">Update See <a href="http://estynedwards.com/blog/2013/09/06/azure-dev-machine-auto-shutdown-part-2/">Part 2</a> for adding SMS Notification and Cancellation</h3>
<h3 id="step-1-install-and-configure-windows-azure-powershell:e2fbb72c5252ed814adc8984c782fa02">Step 1: Install and Configure Windows Azure PowerShell</h3>
<p>Follow the <a href="http://www.windowsazure.com/en-us/manage/install-and-configure-windows-powershell/">instructions</a> on Microsoft&rsquo;s site to configure Azure PowerShell</p>
<h3 id="step-2-create-shutdown-ps1:e2fbb72c5252ed814adc8984c782fa02">Step 2: Create ShutDown.ps1</h3>
<p>You only need a single line to shut down your azure VM</p>
<p><div class="highlight"><pre><span class="nb">Stop-AzureVM</span> <span class="n">-Name</span> <span class="s2">&quot;YourVMName&quot;</span> <span class="n">-ServiceName</span> <span class="s2">&quot;YourServiceName&quot;</span> <span class="n">-Force</span>
</pre></div>
</p>
<p>Note: You have to use PowerShell to shutdown your VM if you don&rsquo;t want to continue paying for it when it is off. When you shutdown from PowerShell or the portal your VM goes into a deallocated state. If you shutdown the VM from the operating system or from the REST API then the VM turns off, but is not deallocated so you continue to be charged.</p>
<p><img src="../Blog1.png" /></p>
<p>If you don&rsquo;t see Deallocated then you are still being charged for your VM.</p>
<h3 id="step-3-setup-the-script-to-run-automatically:e2fbb72c5252ed814adc8984c782fa02">Step 3: Setup the script to run automatically</h3>
<p>The easiest way that I&rsquo;ve found to execute the script is to tie it in to the workstation lock event.</p>
<ul>
<li><p>In the screen saver settings set a timeout value and check &ldquo;On resume, display logon screen&rdquo;
<img src="../Blog12.png " /></p></li>
<li><p>In the task scheduler create a new task named &ldquo;Shutdown&rdquo;</p></li>
<li><p>Create a trigger that fires &ldquo;On workstation lock&rdquo; this will fire when the screen saver turns on.
<img src="../Blog13.png " /></p></li>
<li><p>Create a &ldquo;Start a program&rdquo; actions that points to &ldquo;ShutDown.ps1&rdquo;
<img src="../Blog14.png " /></p></li>
</ul>
<p>Now when the VM&rsquo;s screen saver turns on it will lock the machine and execute the script which will shutdown the VM.</p>