tag:blogger.com,1999:blog-53848572024-03-17T06:53:27.311+00:00Under The StairsThomas Lee's collection of random interesting items, views on things, mainly IT related, as well as
the occasional rantUnknownnoreply@blogger.comBlogger1633125tag:blogger.com,1999:blog-5384857.post-42567465218456517972024-03-04T20:13:00.008+00:002024-03-04T20:24:26.586+00:00Pure Capsaicin at Spiceworks!<p>As many readers know, I've regularly contributed to the Spiceworks online community (<a href="http://www.spiceworks.com/comunity">www.spiceworks.com/comunity</a>) for a long time. As well as contributing I've been a moderator for several forums, including the PowerShell (obviously), Windows, Virtualisation, Azure, and of course DNS. I first joined in August of 1972, found it was fun to contribute (and it was a great place to help IT Pros to get the most out of PowerShell. I've been contributing ever since!</p><p>Contributors get points for doing things withing the comunity, such as posting a new question (10 points), authoring articles that appear on the Comunity home page (50), and providing a best answer to a query (50). I'd point you to the pages that explain it but in the recent upgrade that has just taken place (as I write this article) those pages were lost and all the references inside Google no longer provide the page. Hopefully, that will change.</p><p>To show a contributor's level of contribution, Spiceworks uses has a level system. The level system is based on different peppers of increasing spiciness (as based on the Scoville Scale) - the more points the higher your level of spicenes. New users (aka Spiceheads) start out at the Pimento level (0-100 points), quickly ascending to Sonora (100-250), Anaheim (250-500) and 12 more to reach the pinnacle Pure Capsaicin ( 250.000 points), also known as PC. I'm told that the PC level was originally a theoretical level that no one was expected to ever reach. WRONG</p><p>Reaching the PC level requires a significant contribution over a long time. I was looking at the numbers, and I joined the site just over 4200 days ago, averaging just under 60 points per day over that time period. I have certainly enjoyed the ride so far. I've met some awesome people, had fun helping others and learned a bit along the way. I confess I've also used the forums on a few occasions, to help me troubleshoot issues I encountered in real life. </p><p>What a long strange trip is's been.</p><p><br /></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-43152979659617431652023-02-24T15:53:00.014+00:002023-02-24T20:26:05.776+00:00Having Fun with Get-ContentMost IT Pros know and use the <b>Get-Content</b> to get the contents of a file into a variable/array. You can then process the array to do useful things. I use this cmdlet a lot - in my last book (which has 111 total scripts), I used the cmdlet in over 15|% of the scripts.<div><br /></div><div>Most usage cases involve relatively small files, but sometimes the files can get quite big. And when you import large files, you find that <b>Get-Content</b> is slow. There are a couple of reasons for this blog post shows. One important reason is that <b>Get-Content</b> uses a PowerShell provider - but there is more!</div><div><br /></div><div>As it turns out, you can't use <b>Get-Conten</b>t with the Registry, Certificate, or WSMan providers. And for all but the File System provider, the cmdlet does not return much of value (or return information you could not easily get another way). I would argue almost all usage of the cmdlet is based on the file system provider.</div><div><br /></div><div>As an alternative to using <b>Get-Content</b>, you could use the <b>IO.File</b> .Net class, and invoke the <b>ReadAllLines()</b> method.</div><div><br /></div><div>To test this out, I downloaded a large text file (War and Peace), then tested the two methods of retrieving the text. Here is what I see:</div><div><br /></div><div><span style="font-family: "Fira Code";">PS C:\Foo> # 1. Get War and Peace</span></div><div><div><span style="font-family: Fira Code;">PS C:\Foo> $URI = </span><span style="font-family: "Fira Code";">'http://textfiles.com/etext/FICTION/warpeace.txt'</span></div><div><span style="font-family: Fira Code;">PS C:\Foo> $WAP = Invoke-WebRequest -URI $URI</span></div><div><span style="font-family: Fira Code;">PS C:\Foo> $Outfile = '.\WarAndPeace.txt'</span></div><div><span style="font-family: Fira Code;">PS C:\Foo> $WAP.Content | Out-File -Path $OutFile</span></div><div><span style="font-family: Fira Code;">PS C:\Foo> Get-ChildItem -Path $Outfile</span></div><div><span style="font-family: Fira Code;"><br /></span></div><div><span style="font-family: Fira Code;"> Directory: C:\Foo</span></div><div><span style="font-family: Fira Code;"><br /></span></div><div><span style="font-family: Fira Code;">Mode LastWriteTime Length Name</span></div><div><span style="font-family: Fira Code;">---- ------------- ------ ----</span></div><div><span style="font-family: Fira Code;">-a--- 24/02/2023 15:30 4434672 WarAndPeace.txt</span></div><div><span style="font-family: Fira Code;"><br /></span></div><div><span style="font-family: Fira Code;"><br /></span></div><div><span style="font-family: Fira Code;">PS C:\Foo> # 2. Get the contents into a variable using Get-Content</span></div><div><span style="font-family: Fira Code;">PS C:\Foo> $M1 = Measure-Command -Expression {</span></div><div><span style="font-family: Fira Code;"> $File1 = Get-Content $Outfile</span></div><div><span style="font-family: Fira Code;"> }</span></div><div><span style="font-family: Fira Code;">PS C:\Foo> "Using Get-Content took {0:n2} milliseconds" -f $M1.TotalMilliSeconds</span></div><div><span style="font-family: Fira Code;"><b><u>Using Get-Content took 663.80 milliseconds</u></b></span></div><div><span style="font-family: Fira Code;">PS C:\Foo></span></div><div><span style="font-family: Fira Code;">PS C:\Foo> # 3. Now with .NET</span></div><div><span style="font-family: Fira Code;">PS C:\Foo> $M2 = Measure-Command -Expression {</span></div><div><span style="font-family: Fira Code;"> $File2 = [IO.File]::ReadAllLines($Outfile)</span></div><div><span style="font-family: Fira Code;"> }</span></div><div><span style="font-family: Fira Code;">PS C:\Foo> "Using Native .net {0:n2} milliseconds" -f $M2.TotalMilliSeconds</span></div><div><span style="font-family: Fira Code;"><b><u>Using Native .net 91.14 milliseconds</u></b></span></div><div><br /></div></div><div>As you can see, using the native method is a lot faster (nearly 6 times faster). But why is this?</div><div><br /></div><div>Well, the first reason is that using a provider is just slower. But another reason <b>Get-Content</b> is so much slower is that it adds several properties to every line returned. You can see this as follows:</div><div><br /></div><div><div><span style="font-family: Fira Code;">PS C:\Foo> # 4. look at output types</span></div><div><span style="font-family: Fira Code;">PS C:\Foo> "Get-Content produces a $($File1.GetType().FullName) object"</span></div><div><span style="font-family: Fira Code;"><b><u>Get-Content produces a System.Object[] object</u></b></span></div><div><span style="font-family: Fira Code;">PS C:\Foo> ".NET produces a $($File2.GetType().Fullname) object"</span></div><div><span style="font-family: Fira Code;"><b><u>.NET produces a System.String[] object</u></b></span></div><div><span style="font-family: Fira Code;">PS C:\Foo> </span></div><div><span style="font-family: Fira Code;">PS C:\Foo> # 5. And look at what Get-Content does for us:</span></div><div><span style="font-family: Fira Code;">PS C:\Foo> $File1 | Get-Member -MemberType Properties</span></div><div><span style="font-family: Fira Code;"><br /></span></div><div><span style="font-family: Fira Code;"> TypeName: System.String</span></div><div><span style="font-family: Fira Code;"><br /></span></div><div><span style="font-family: Fira Code;">Name MemberType Definition</span></div><div><span style="font-family: Fira Code;">---- ---------- ----------</span></div><div><span style="font-family: Fira Code;">PSChildName NoteProperty string PSChildName=WarAndPeace.txt</span></div><div><span style="font-family: Fira Code;">PSDrive NoteProperty PSDriveInfo PSDrive=C</span></div><div><span style="font-family: Fira Code;">PSParentPath NoteProperty string PSParentPath=C:\Foo</span></div><div><span style="font-family: Fira Code;">PSPath NoteProperty string PSPath=C:\Foo\WarAndPeace.txt</span></div><div><span style="font-family: Fira Code;">PSProvider NoteProperty ProviderInfo PSProvider Microsoft.PowerShell.Core\FileSystem</span></div><div><span style="font-family: Fira Code;">ReadCount NoteProperty long ReadCount=1</span></div><div><span style="font-family: Fira Code;">Length Property int Length {get;}</span></div><div><span style="font-family: Fira Code;"><br /></span></div><div><span style="font-family: Fira Code;">PS C:\Foo> $File2 | Get-Member -MemberType Properties</span></div><div><span style="font-family: Fira Code;"><br /></span></div><div><span style="font-family: Fira Code;"> TypeName: System.String</span></div><div><span style="font-family: Fira Code;"><br /></span></div><div><span style="font-family: Fira Code;">Name MemberType Definition</span></div><div><span style="font-family: Fira Code;">---- ---------- ----------</span></div><div><span style="font-family: Fira Code;">Length Property int Length {get;}</span></div></div><div><br /></div><div>As you can see, <b>Get-Content</b> returns an object array of strings - where each member (ie each line of the text file) has 7 additional properties over and beyond what is in a string array. So if you import a 56,859-line text file, <b>Get-Content</b> adds 390,013 properties to the array that pretty much NO one needs or uses. And that takes time.</div><div><br /></div><div>So, if you are using <b>Get-Content</b> to retrieve text from a file, and performance is important, consider using .NET.</div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-62825269893373436952023-02-02T14:43:00.002+00:002023-02-02T14:43:25.019+00:00My Latest (last?) PowerShell Book is published!This week I got the news that my latest PowerShell book has been published and is available for order:<div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG35map-4f6kfRdIVr6YtYsVk2UXXJ2c_cZEYBZu1XNuBrhuUnQSIQyhodpMxsZSLFr2Hve9O5iDkZRa5fXX1JaivPlkPKWCm1HwJfRhMjacs6Ud6XGa_9jlmLvTv65akg2Ij-qxG3G9_t5sPI7CFZW1qbChE_9QmSXjq_BHOgb2F2bBPAXi4/s689/COVER.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="689" data-original-width="559" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG35map-4f6kfRdIVr6YtYsVk2UXXJ2c_cZEYBZu1XNuBrhuUnQSIQyhodpMxsZSLFr2Hve9O5iDkZRa5fXX1JaivPlkPKWCm1HwJfRhMjacs6Ud6XGa_9jlmLvTv65akg2Ij-qxG3G9_t5sPI7CFZW1qbChE_9QmSXjq_BHOgb2F2bBPAXi4/w325-h400/COVER.png" width="325" /></a></div><div class="separator" style="clear: both; text-align: left;">You can order it today from all the usual places, including <a href="https://smile.amazon.co.uk/Windows-Server-Automation-PowerShell-Cookbook/dp/1804614238">https://smile.amazon.co.uk/Windows-Server-Automation-PowerShell-Cookbook/dp/1804614238</a>.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">This book updates earlier editions and covers, specifically, PowerShell 7.2 (as an LTS release) and Windows Server 2022. It should also be useful if you are using PowerShell 7 on earlier versions of Windows Server too. </div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Here is the table of contents:</div><div class="separator" style="clear: both; text-align: left;"><ol class="a-ordered-list a-vertical" style="background-color: white; box-sizing: border-box; color: #0f1111; font-family: "Amazon Ember", Arial, sans-serif; font-size: 14px; margin: 0px 0px 0px 28px; padding: 0px;"><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Installing and Configuring PowerShell 7</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Managing PowerShell 7 in the Enterprise</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Exploring .NET</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Managing Active Directory</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Managing Networking</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Implementing Enterprise Security</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Managing Storage</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Managing Shared Data</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Managing Printing</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Exploring Windows Containers</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Managing Hyper-V</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Debugging and Troubleshooting Windows Server</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Managing Window Server with Window Management Instrumentation (WMI)</span></li><li style="box-sizing: border-box; list-style: decimal; margin: 0px; overflow-wrap: break-word;"><span class="a-list-item" style="box-sizing: border-box;">Managing Windows Update Services</span></li></ol></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">An addition is a chapter on WSUS. The WSUS module is one of the three modules you can not use within PowerShell 7. You can not load the module natively within a PowerShell 7 since the .NET APIs that the module relies on are unavailable (in .Net) Additionally, the normal Windows PowerShell compatibility mechanism does not work with this module because the WSUS module is based on methods and not actual cmdlets. With WSUS, you instantiate the WSUS server instance of the server you wish to manage, then use that object's methods. With the compatibility solution, you do not have access to the methods. </div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">There IS a way around this - you can create a remoting session to a Windows PowerShell endpoint and do all the work within that session. It is a bit more work: you create the remoting session, create script blocks that perform WSUS management activities, then execute those script blocks within the session.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">My publisher is looking for potential reviewers - you get a copy in exchange for writing a review. Contact me if you are interested.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div><br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-6745509314607675532022-06-16T15:28:00.000+01:002022-06-16T15:28:05.497+01:00More Hyper-V Troubleshooting Woes - but a script to help<p>I<a href="https://tfl09.blogspot.com/2022/05/fun-and-games-with-hyper-v-in-windows-11.html" target="_blank">n a previous post,</a> I noted some challenges I faced with Hyper-V. The TL;DR is that Windows Update breaks Hyper-V, often as a result of a new WIndows Insider Build. In that post I explained the basic fix for this issue. </p><p>Jeffrey Snover once pointed out that when Linux guys are faced with an issue for a second time - they create a script. Well - I am now facing this Hyper-V problem more frequently. The root issue is that an Update can break Hyper-V. The solution is to re-create the VMs. Which can be a lot of work.</p><p>As I recovered from the previous failure, I started to write a script to so many of the actions. This week, I had ANOTHER update (WSL) that broke Hyper-V. So to recover, I write the script below. I hope you find is useful.</p><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; font-size: 14px; line-height: 19px; white-space: pre;"><div><span style="color: green;"># fixing hyperv</span></div><div><span style="color: green;"># a script in several parts</span></div><br /><div><span style="color: green;"># part 1 - remove Hyper-V from Win 11</span></div><div><span style="color: green;"># run in elevated command prompt</span></div><br /><div><span style="color: green;"># 1.1 View what is there</span></div><div>Get-windowsoptionalFeature -FeatureName Microsoft-hyper-V* -online |</div><div> Format-Table -Property *Name,State</div><br /><div><span style="color: green;"># 1.2 Remove the Hyper-V optionalfeature </span></div><div>Get-windowsoptionalFeature -FeatureName Microsoft-hyper-V* -online |</div><div> Disable-WindowsOptionalFeature -Online</div><br /><br /><div><span style="color: green;"># note this pops up a 'do you want to reboot' - say yes/. </span></div><div><span style="color: green;">#</span></div><div><span style="color: green;"># Note the reboot may fail (trying and not succeeding to stop the hyper-V service)</span></div><br /><br /><div><span style="color: green;"># Step 2. After the reboot from step 1</span></div><br /><div><span style="color: green;"># 2.1 View Hyper-V Data Folder</span></div><div>$DataBase = <span style="color: #a31515;">"$env:ProgramData\Microsoft\Windows\Hyper-V"</span></div><div>Get-ChildItem -Path $DataBase</div><br /><div><span style="color: green;"># 2.2 Remove the Hyper-V Data</span></div><div>Get-ChildItem -Path $DataBase -recurse |</div><div> Remove-Item -Recurse -Force</div><br /><div><span style="color: green;"># 2.3 Check the features</span></div><div>Get-windowsoptionalFeature -FeatureName Microsoft-hyper-V* -online |</div><div>Format-Table -Property *Name,State </div><br /><div><span style="color: green;"># 2.4 Re-Add Hyper-V to Windows and Reboot</span></div><div>Get-WindowsOptionalFeature -FeatureName Microsoft-hyper-V* -online</div><div>| Enable-WindowsOptionalFeature -Online</div><br /><div><span style="color: green;"># Reboot</span></div><br /><br /><div><span style="color: green;"># Step 3 - Creater New Switchs</span></div><br /><div>New-VMSwitch -Name Internal -SwitchType Internal</div><br /><div>$NIC = Get-NetAdapter | <span style="color: blue;">where</span> {($_.status -eq <span style="color: #a31515;">'up'</span>) -and ($_.Name -notmatch <span style="color: #a31515;">'vEthernet'</span>)}</div><div>New-VMswitch -Name External -NetadapterName $Nic.Name -AllowManagementOS:<span style="color: blue;">$true</span></div><br /><br /><div><span style="color: green;"># Step 4 - recreate the VMs</span></div><br /><div><span style="color: green;"># At this point, you may need to merge any difference disks. So far I have not automated this</span></div><div><span style="color: green;"># So use the GUI</span></div><br /><br /><br /><div><span style="color: green;"># Cookham1</span></div><div>$vmbase = <span style="color: #a31515;">'D:\VMs\Cookham1'</span></div><div>$Vhdx = <span style="color: #a31515;">"$VMbase\Virtual Hard Disks\Cookham1.vhdx"</span></div><div>New-VM -VHDPath $vhdx -Generation <span style="color: #098658;">2</span> -MemoryStartupBytes <span style="color: #098658;">8</span><span style="color: blue;">gb</span> -Name <span style="color: #a31515;">"Cookham1"</span> -Path $vmbase</div><div>Start-VM -VMName <span style="color: #a31515;">'Cookham1'</span></div><br /><br /><br /><div><span style="color: green;"># Reskit VMs</span></div><div><span style="color: green;"># DC1</span></div><div>$vmbase = <span style="color: #a31515;">'D:\v9\DC1'</span></div><div>$Vhdx = <span style="color: #a31515;">"$VMbase\dc1.vhdx"</span></div><div>New-VM -VHDPath $vhdx -Generation <span style="color: #098658;">2</span> -MemoryStartupBytes <span style="color: #098658;">8</span><span style="color: blue;">gb</span> -Name DC1 -Path $vmbase</div><div>Start-VM -VMName dc1</div><br /><div><span style="color: green;"># DC2</span></div><div>$vmbase = <span style="color: #a31515;">'D:\v9\DC2'</span></div><div>$Vhdx = <span style="color: #a31515;">"$VMbase\dc2.vhdx"</span></div><div>New-VM -VHDPath $vhdx -Generation <span style="color: #098658;">2</span> -MemoryStartupBytes <span style="color: #098658;">8</span><span style="color: blue;">gb</span> -Name DC2 -Path $vmbase</div><div>Start-VM -VMName DC2</div><br /><div><span style="color: green;"># SRV1</span></div><div>$vmbase = <span style="color: #a31515;">'D:\v9\SRV1'</span></div><div>$Vhdx = <span style="color: #a31515;">"$VMbase\SRV1.vhdx"</span></div><div>New-VM -VHDPath $vhdx -Generation <span style="color: #098658;">2</span> -MemoryStartupBytes <span style="color: #098658;">6</span><span style="color: blue;">gb</span> -Name SRV1 -Path $vmbase</div><div>Start-VM -VMName SRV1</div><br /><br /><div><span style="color: green;"># SRV2</span></div><div>$vmbase = <span style="color: #a31515;">'D:\v9\SRV2'</span></div><div>$Vhdx = <span style="color: #a31515;">"$VMbase\SRV2.vhdx"</span></div><div>New-VM -VHDPath $vhdx -Generation <span style="color: #098658;">2</span> -MemoryStartupBytes <span style="color: #098658;">6</span><span style="color: blue;">gb</span> -Name SRV2 -Path $vmbase</div><div>Start-VM -VMName SRV2</div><br /><br /><div><span style="color: green;"># UKDC1</span></div><div>$vmbase = <span style="color: #a31515;">'D:\v9\UKDC1'</span></div><div>$Vhdx = <span style="color: #a31515;">"$VMbase\UKDC1.vhdx"</span></div><div>New-VM -VHDPath $vhdx -Generation <span style="color: #098658;">2</span> -MemoryStartupBytes <span style="color: #098658;">6</span><span style="color: blue;">gb</span> -Name UKDC1 -Path $vmbase</div><div>Start-VM -VMName UKDC1</div><br /><div><span style="color: green;"># Step 5. reset networking</span></div><br /><div><span style="color: green;"># On DC1.DC2 - turn OFF the DHCP serice temporarily!</span></div><div><span style="color: green;"># Remove all Reservations and zones</span></div><br /><div><span style="color: green;"># Then On a VM by VM basis:</span></div><div><span style="color: green;"># Open the VM'S Hyperv- Settings and remove Nics</span></div><div><span style="color: green;"># In the VM, use Device manager, view hidden devices and Remove ALL the Hyper-V NICS</span></div><div><span style="color: green;"># In the VM's Settings - add two nics: Internal (Ethernet) and External (Ethernet #2)</span></div><div><span style="color: green;"># Re-configure the Internal statisc NIC's IP address (see reskitnetowrk.ms)</span></div><br /><br /><div><span style="color: green;"># Recreate the DHCP Scopes and reservations and test</span></div><br /><div><span style="color: green;"># Test internal communicationns (from VM to each DC and server)</span></div><div>Test-NetConnection DC1</div><div>Test-NetConnection DC2</div><div>Test-NetConnection UKDC1</div><div>Test-NetConnection SRV1</div><div>Test-NetConnection SRV2</div><br /><br /><br /><br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-36294999036070463852022-05-24T15:52:00.008+01:002023-05-13T11:27:17.563+01:00Troubleshooting Hyper-V in Windows 11<p> I love Hyper-V inside Windows 11 (and inside Windows 8.x and 10 in their day). An utterly simple hypervisor (to use) but one that provides a lot of benefits. I have written 4, and shortly 5, books that made use of this feature. I have created a nice server farm (2 forests, 3 domains, multiple servers, etc) which runs nicely on my boxes. The scripts to create the VMs, and configure them are all published to GitHub,. </p><p>Now to run a VM at a reasonable speed, you need to give the VM resources. My old Precision T7500 did not and could not support the hardware necessary for Win 11. I now have a Precision T7920 with 2 16-core Xeon Gold processors, 128 GB of ram, 1 TB of Nvme SSD, 2x2TB plus 1x1TB SSDs. So a LOT of storage, a LOT of memory, and a lot OF CPU. My farm works great. Except when it doesn't.</p><p>I run this box as part of the Windows Insider's program. That means I get a more-or-less weekly upgrade that brings new features and bug fixes. It is a lot of fun - except sometimes the upgrade does NOT work. Over the years I have had numerous issues with an upgrade and have generally been able to back up to an earlier build or take a newer build (with a fix). For the most part this has been an inconvenience to me, but useful for the program for a while - I just love providing feedback.</p><p>One specific set of issues caused by an updated Insider build is that Hyper-V does not work. This has happened now around 5 times over the years. <b>NOTE: This was originally written in 2002. Since this blog post was first published, this issue has affected nearly every Windows Insider update I have taken since.</b></p><p>Backing up to an earlier build sometimes cures the problems. But all to often, I just could not get things going again. This happend again a few days ago - and this blog post notes some of the issues and some troubleshooting tips (at that time).</p><p>So after an upgrade, starting the Hyper-V MMC showed something like this:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUTriE3RaR8yKcdhxDA3uL7Pj6N-_MyAN3-JTBgJfGh-rF0jpykyOy5DSbsHJxoK2ekcY2dRt86pIwZbswCFj_7miu7S1z8QWCx_SgOB3D4InFhxvvzG5K1k2KaMTbJ5gV2jg783PLr0xCS5RZqw_mKwQ1XDyhqdv5K7hRYDow77bXS4sswrg/s1451/2022-05-23_11-42-45.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1118" data-original-width="1451" height="372" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUTriE3RaR8yKcdhxDA3uL7Pj6N-_MyAN3-JTBgJfGh-rF0jpykyOy5DSbsHJxoK2ekcY2dRt86pIwZbswCFj_7miu7S1z8QWCx_SgOB3D4InFhxvvzG5K1k2KaMTbJ5gV2jg783PLr0xCS5RZqw_mKwQ1XDyhqdv5K7hRYDow77bXS4sswrg/w482-h372/2022-05-23_11-42-45.png" width="482" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div>As I hope you can see, the MMC is showing two VMs trying to start. One is stuck at restoring (10%), the other at just restoring. Trying to stop a VM from PowerShell was also not successful. <div><br /></div><div><b>Troubleshooting tip #1</b></div><div><br /></div><div><i>As long as you have the VHDX(s), you can always rebuild the VM. And if you created the VM with a PowerShell script, re-creating it is trivial.</i></div><div><br /></div><div>So with that in mind, I did the obvious thing: I uninstalled Hyper-V totally and rebooted. Then, I "hid" the folders containing my VMs and re-installed Hyper-V. My thinking was that this would clear everything away, and I could unhide the VM folders and re-import the VMs. Except it didn't work/</div><div><br /></div><div>Having removed then re-added Hyper-V did NOT clear down the configuration. In fact, what I now see is:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc5l0EaQRC3HNiuSXzrFLBiOsbbG_yGd7hyKgl6s-1aGaHOEQs02ox3R9BKpBE0cDDDB-95rqbnLIET7mpLVdus670ZuPTx16NaWYlhgeaad8A6bLevIjhOlbb1wtFzoZeLc6ZqiM5OZx6BQAHJ-mYHr23t7O-N7lU7_zC_bnTmbYarE51JSk/s939/2022-05-21_14-55-52.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="265" data-original-width="939" height="119" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc5l0EaQRC3HNiuSXzrFLBiOsbbG_yGd7hyKgl6s-1aGaHOEQs02ox3R9BKpBE0cDDDB-95rqbnLIET7mpLVdus670ZuPTx16NaWYlhgeaad8A6bLevIjhOlbb1wtFzoZeLc6ZqiM5OZx6BQAHJ-mYHr23t7O-N7lU7_zC_bnTmbYarE51JSk/w424-h119/2022-05-21_14-55-52.png" width="424" /></a></div><div><br /></div>So even though I removed and re-added Hyper-V (and hid all the folders containing the VMs/VHDXs) Hyper-V still remembered the old VMs. This seemed illogical until a nice MS person explained it as the de-installation does not take <i>everything</i> related to Hyper-V off your box - in case you want to reinstall it - your configuration magically reappears. <div><br /></div><div><br /></div><div><div><b>Troubleshooting tip #2 and #3</b></div><div><br /></div><div>A conversation on Twitter led to the discovery. <i>The list of VMs that the MMC uses when it starts up is contained in a file: <b>$env:ProgramData\Microsoft\Windows\Hyper-V\data.vmcx</b> although it was different in earlier versions of Windows.</i></div><div><br /></div><div><i>The second troubleshooting tip: is that it is in binary form, so hand editing is not really possible. I was also told that removing the file totally was a bad idea since it contains other valuable data, too.</i></div><div><br /></div><div>So how to recover? </div><div><br /></div><div><b>Troubleshooting tip #4</b></div><div><br /></div><div><i>As noted, the details of the VMs and Hyper-V itself are, by default, contained in a folder (with sub-folders) at <b>$env:ProgramData\Microsoft\Windows\Hyper-V.</b> So to get back to a pristine state, remove the Hyper-V feature from Windows 11. After the reboot, remove this folder totally then re-install Hyper-V and reboot. After the reboot, you should see a nice clean MMC console!</i></div></div><div><br /></div><div><span style="font-family: inherit;">With a pristine Hyper-V environment, I have to re-create the virtual switches and then re-create the VMs. It appears that removing the Hyper-V feature deletes all the VM data except the actual VHDXs themselves. So recreating the VMs meant just building a new VM that contained the old VHDX. </span></div><div><span style="font-family: inherit;"><br /></span></div><div><span style="font-family: inherit;">There was only one final problem - networking. If you remove a vNIC from a VM, and then add a new NIC, Windows sees the new NIC as, well, a NEW NIC and creates a new configuration for it. But it also keeps the old configuration. This can cause some issues, including not letting you rename the connection inside <b>ncpa.cpl</b> - Windows claims another connection already has that game. </span></div><div><br /></div><div>If you open Device Manager, you see just the most recently added vNIC, something like this:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3QRJ_dUlEXC9BQTNu0m0yjX6wBeIo_O19YsWgy3egEf00rwxx8GvajHTa06iloS1zSxrxfXDajv4ClCP6eageOyRp_ZF0lccjaY_YNp6XJJXTaKjgiheQ6UOrLAWPLvsdtIgKz6-T1to71DWm8rklpkVZ6iLFr7o3HutPh-njyXtTDcMbDYM/s804/2022-05-24_14-49-43.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="348" data-original-width="804" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3QRJ_dUlEXC9BQTNu0m0yjX6wBeIo_O19YsWgy3egEf00rwxx8GvajHTa06iloS1zSxrxfXDajv4ClCP6eageOyRp_ZF0lccjaY_YNp6XJJXTaKjgiheQ6UOrLAWPLvsdtIgKz6-T1to71DWm8rklpkVZ6iLFr7o3HutPh-njyXtTDcMbDYM/w484-h210/2022-05-24_14-49-43.png" width="484" /></a></div><br /><div><br /></div><div><p><b>Troubleshooting tip #5</b></p><p><i>If you enable hidden devices inside Device Manager you can see the "removed" net adapters.</i></p><p>In Device Manager, click on <b>View</b>, then select <b>Show Hidden Devices</b> then you see:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ5-Lp_2e3F9fF00-G-KLbiOFkpaF946nVGlWAF_KnYzFU6sNdh8c0e5_qtChJ2NMc9KOOAznjNIH8wmSq-ZOq-MljId4sx1RMFeedu83f0pzFKkVcpJtpszesrl8TKgNfInEy9_rgKYsxmrLc3ExfPVHukryUypZFQVDkK_fbvWTq1xXIgO0/s574/2022-05-24_14-48-41.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="574" data-original-width="456" height="523" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ5-Lp_2e3F9fF00-G-KLbiOFkpaF946nVGlWAF_KnYzFU6sNdh8c0e5_qtChJ2NMc9KOOAznjNIH8wmSq-ZOq-MljId4sx1RMFeedu83f0pzFKkVcpJtpszesrl8TKgNfInEy9_rgKYsxmrLc3ExfPVHukryUypZFQVDkK_fbvWTq1xXIgO0/w415-h523/2022-05-24_14-48-41.png" width="415" /></a></div><br /><p>You can then right-click each adapter and uninstall the device. If you then click <b>Action</b>, and then click<b> Scan for hardware changes</b> - you should see just the actual vNICs in your VM.</p><p><b>Troubleshooting tip #6</b></p><p><i>If you add a 'new' nic to a VM, Windows sees it as a brand new NIC, so sets the device to get its configuration from DHCP.</i> </p><p>This might be fine if the host was DHCP configured but not if you configured it with static IP addresses (eg for a DC or a DNS server). Fortunately, you have PowerShell and can easily script the NIC configuration. </p><p>I hope this helps someone!</p><p><i><b>[note: this issue has been with me for a long while. This post was first written in May 2002, but the underlying issue has been consistent since them. I have made some updates (and fixed typos) to this post in May 2023.</b></i></p><p><br /></p><div><b><br /></b></div><p><br /></p></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-60026689752529255852022-03-19T15:45:00.000+00:002022-03-19T15:45:42.930+00:00Configuring PowerShell 7 With Group Policy<h3 style="text-align: left;">Introduction</h3><p>Group policy is a feature of Windows Server Active Directory which automagically deploys groups of policies to users and computers. A policy is some computer setting you wish to enforce, such as which screen saver to use, what desktop background to use, or what the default execution policy should be. </p><p>Windows PowerShell has for a while allowed you to set certain group policies to control how PowerShell works. Windows PowerShell 5.1 provides five specific policy settings. PowerShell 7 provides all the Windows PowerShell policies, plus one more. I describe each policy below. </p><p>One neat feature of PowerShell 7 is that you can enable independent policy values for PowerShell 7 and Windows PowerShell. Or you can enable a PowerShell 7 policy and take any values, such as the Execution Policy from Windows PowerShell policies.</p><p>You can set policies for a computer or a user. I base the Group Policy Editor and the PowerShell cmdlets make use of administrative templates stored <b><span style="font-family: courier;">C:\Windows\PolicyDefinitions</span></b> folder in your DC (or to a central policy store shared on all DCs). The templates include an XML file that defines a policy or set of policy, which has the extension ADMX. Each template definition a localised set of strings stored in an ADML file. The ADMX file contains pointers to strings defined in the ADML file. Having both files enables the GP Editor to use localised language.</p><p>After you apply a policy, the group policy agent on the computer creates entries in the user or computer's registry policy area. You can see the policy if you use registry editor or PowerShell and navigate to <span style="font-family: courier;"><b>HKCU:\Software\Policies\Microsoft\PowerShellCore</b></span> for user settings, or you can navigate to <b><span style="font-family: courier;">HKLM:\Software\Policies\Microsoft\PowerShellCore</span></b> for computer settings.</p><p>The group policy agent runs each time the computer starts, and each time a user logs on. The agent also runs at intervals of 2 hours (less a random time up to 30 minutes). To immediately invoke the agent, you can use the <span style="font-family: courier;"><b>gpupdate.exe</b></span> console application. </p><p><b>NOTE: </b>This article started out simple, but as it grew, I've had to split it into two. In this article, I look at the GPO settings you can specify and which registry key(s) and value entries they use. Armed with this information, the next article looks at how you set each policy using PowerShell 7. </p><h3 style="text-align: left;">PowerShell Group Policy settings</h3><p>There are six PowerShell 7 related group policies you can deploy</p><p></p><ul style="text-align: left;"><li>Execution Policy</li><li>Console Session Configuration (new with PowerShell 7)</li><li>Module Logging</li><li>Script block logging</li><li>Transcription</li><li>Updatable Help.</li></ul><br /><h3 style="text-align: left;">Setting Policies</h3><div>Before setting any policy, note that each policy sets one or more keys and value entries in the user or computer section of the registry. Most policies are a single registry key with one or more value entries. Let's look at the individual policies, and the registry keys and value entries deployed.</div><div><br /></div><div>Since these policies are registry settings, you can deploy them using group policy, or you can set the registry key manually. You could use a .REG file containing the settings you want to apply to a host, or use PowerShell to set the keys and value entries needed for the policy. </div><div><br /></div><div>In the following section, I show how you can create the key and value entries needed for user settings of a policy. In the next article, you can see how to create and deploy the group policy settings using PowerShell cmdlets. </div><div><br /></div><h3 style="text-align: left;">Execution Policy</h3><div>The Execution Policy policy defines a particular execution policy or whether to disallow all script execution. I would expect you to know that PowerShell's Execution Policy is <i>not</i> a security barrier. More a speed bump to stop a very in-experienced user to do something silly. I would hope you know it is pretty easy to work around a restricted execution policy. </div><div><br /></div><div>For most organisations, an Execution Policy of <b><span style="font-family: courier;">RemoteSigned</span></b> is probably sufficient. Your IT Professionals might want to log in and have full access without having to work around a more restricted policy, so setting the policy to <b><span style="font-family: courier;">Unrestricted</span></b> for members of the IT department might be useful. Mileage varies. </div><div><br /></div><div>The registry key set by the policy is<br /><span style="font-family: courier;">HKCU:\Software\Policies\Microsoft\PowerShellCore</span></div><div>This is for the user policy setting. If you are setting computer policies, you can use <span style="font-family: courier;">HKLM</span>: instead, which is the case with all the other policy keys used.</div><div><span style="font-family: courier;"><br /></span></div><div>There are two value entries for this policy:</div><div><div><ul style="text-align: left;"><li><span style="font-family: courier;">EnableScripts</span> - This value entry enables this policy. It is of type <b>dword</b> and has a value of 1 if the policy is enabled </li><li><span style="font-family: courier;">ExecutionPolicy</span> - This is the execution policy to be applied. It is a <b>string</b> and can contain any valid PowerShell execution policy </li></ul><div>Here is how to set this policy using PowerShell, in HKCU:</div></div></div><div><div><div style="background-color: white; font-size: 14px; line-height: 19px; white-space: pre;"><span style="color: green;"></span></div></div><blockquote><div><div style="background-color: white; font-size: 14px; line-height: 19px; white-space: pre;"><div><span style="color: #660000; font-family: courier;"><b># 1. Set Execution Policy</b></span></div><div><span style="color: #660000; font-family: courier;"><b># Create Key</b></span></div><div><span style="color: #660000; font-family: courier;"><b>$Key = 'HKCU:\Software\Policies\Microsoft\PowerShellCore'</b></span></div><div><span style="color: #660000; font-family: courier;"><b>if (Test-Path $Key) {</b></span></div><div><span style="color: #660000; font-family: courier;"><b> Write-Verbose "Registry Key exists [$key]"</b></span></div><div><span style="color: #660000; font-family: courier;"><b>}</b></span></div><div><span style="color: #660000; font-family: courier;"><b>Else {</b></span></div><div><span style="color: #660000; font-family: courier;"><b> Write-Verbose "Creating registry key [$key]"</b></span></div><div><span style="color: #660000; font-family: courier;"><b> New-Item -Path $Key</b></span></div><div><span style="color: #660000; font-family: courier;"><b>}</b></span></div><div><span style="color: #660000; font-family: courier;"><b># Set value for execution policy </b></span></div><div><span style="color: #660000; font-family: courier;"><b>Write-Verbose 'Setting Execution Policy On'</b></span></div><div><span style="color: #660000; font-family: courier;"><b>$CVHT1 = @{ Path = $Key</b></span></div><div><span style="color: #660000; font-family: courier;"><b> Name = 'EnableScripts'</b></span></div><div><span style="color: #660000; font-family: courier;"><b> Type = 'Dword'</b></span></div><div><span style="color: #660000; font-family: courier;"><b> Value = 1 }</b></span></div><div><span style="color: #660000; font-family: courier;"><b>Set-ItemProperty @CVHT1</b></span></div><div><span style="color: #660000; font-family: courier;"><b>Write-Verbose 'Setting Execution Policy to Unrestricted'</b></span></div><div><span style="color: #660000; font-family: courier;"><b>$CVHT2 = @{ Path = $Key</b></span></div><div><span style="color: #660000; font-family: courier;"><b> Name = 'ExecutionPolicy'</b></span></div><div><span style="color: #660000; font-family: courier;"><b> Type = 'String'</b></span></div><div><span style="color: #660000; font-family: courier;"><b> Value = 'Unrestricted'}</b></span></div><div><span style="color: #660000; font-family: courier;"><b>Set-ItemProperty @CVHT2</b></span></div></div></div><div></div></blockquote><div><br /></div><div><br /></div></div><p></p><h3 style="text-align: left;">Console Session Configuration </h3>The Console Session Configuration specifies a remoting configuration endpoint to use. Remote sessions then run against that endpoint. You can specify any endpoint, include a JEA endpoint.<div><div><br /></div><div>The registry key set by this policy is:</div><div><div><br /></div><div><span style="font-family: courier;"><b>HKCU:Software\Policies\Microsoft\PowerShellCore\ConsoleSessionConfiguration</b></span></div><div><br /></div><div>There are two value entries for this key:</div></div><div><div><ul style="text-align: left;"><li><span style="font-family: courier;">EnableConsoleSessionConfiguration</span> - this entry enables the policy. It is of type <b>dword </b>and has a value of 1 to indicate that the policy is applied.</li><li><span style="font-family: courier;">ConsoleSessionConfigurationName</span> - this entry is the remoting endpoint that is used. It is a <b>string,</b> such as "PowerShell.7". </li></ul><div><br /></div></div><div><h3 style="text-align: left;">Module Logging</h3></div><div>Module Logging requires PowerShell to log module usage and for which modules. If you set this policy, PowerShell logs pipeline execution events for the specified modules to the PowerShell Core event log. </div><div><br /></div><div>Be careful with this setting as you could generate a lot of log entries. If you are going to log module events, have a strategy for reviewing the events generate</div><div><br /></div><div>This policy requires the use of two registry keys. The first is:</div><div><span style="font-family: courier;"><b>HKCU:\Software\Policies\Microsoft\PowerShellCore\ModuleLogging </b></span></div><div><div><br /></div><div>There is one value entry for this key:</div></div><div><ul style="text-align: left;"><li><span style="font-family: courier;">EnableModuleLogging</span> - This entry enables the policy. It is of type <b>dword </b>and has a value of 1 to indicate that the policy is applied.</li></ul></div><div><br /></div><div>The second key used by this policy is:</div><div><br /></div><div><span style="font-family: courier;"><b>HKCU:\Software\Policies\Microsoft\PowerShellCore\ModuleLogging\ModuleNames</b></span></div><div><br /></div><div>There are multiple value entries you can specify for this key, each one a module for logging. Each value entry has a name and a value of the module name. So if you wanted to log events for the <span style="font-family: courier;">FOO42</span> module, you would have a registry value name <b><span style="font-family: courier;">FOO42</span></b> with an associated value of <b><span style="font-family: courier;">FOO42</span></b>. You can specify as many modules as you like.</div><div><div><ul></ul></div></div><div><h3 style="text-align: left;">Script block logging</h3>You use the Script block logging policy to turn on PowerShell's logging of any important script blocks. PowerShell does not log all script blocks only those that change something. Nevertheless, this policy can generate a lot of logging. In Windows PowerShell, setting this policy could result in performance degradation although has been much improved in PowerShell 7.</div><div><div><br /></div><div>The registry key used by this policy is:</div><div><br /></div><div><span style="font-family: courier;"><b>HKCU:Software\Policies\Microsoft\PowerShellCore\ScriptBlockLogging</b></span></div></div><div><span style="font-family: courier;"><b><br /></b></span></div><div><div><span style="font-family: inherit;">There is one value entry under this policy.</span></div><div><ul style="text-align: left;"><li><span style="font-family: courier;">EnableScriptBlockLogging</span> - This entry enables the policy. It is of type <b>dword </b>and has a value of 1 to indicate that the policy is applied.</li></ul></div><div><ul></ul></div></div><div><h3 style="text-align: left;">Transcription</h3><div>The Transcription policy allows you to automatically create a transcript of every PowerShell session. </div><div><div><br /></div><div>The registry key set by this policy is:</div><div><b><span style="font-family: courier;">HKCU:\Software\Policies\Microsoft\PowerShellCore\Transcription</span></b></div><div><br /></div><div>There are two value entries used by this policy:</div><div><ul style="text-align: left;"><li><b><span style="font-family: courier;">EnableTranscripting</span></b> - This entry enables the policy. It is of type <b>dword </b>and has a value of 1 to indicate that the policy is applied.</li><li><span style="font-family: courier;"><b>OutputDirectory</b></span> - this is a <b>string</b> and specifies the folder in which PowerShell writes session transcripts. </li></ul><br /></div></div><h3 style="text-align: left;">Updatable Help</h3></div><div>The Updatable Help policy allows you to configure a default value fore <b>Update-Help</b>'s parameter <b>SourcePath</b>. If you enable the policy, <b>Update-Help</b> uses the setting as a default location for new help information. You can always override this by specifying a different value for the source path when you run <b>Update-Help</b>.</div><div><br /></div><div>The registry key set by this policy is:</div><div><br /></div><div><span style="font-family: courier;"><b>HKCU:\Software\Policies\Microsoft\PowerShellCore\UpdatableHelp</b></span></div><div style="text-align: left;"><b><span style="font-family: inherit;"><br /></span></b></div><div style="text-align: left;"><span style="font-family: inherit;">There are two value entries under this policy.</span></div><div><div><ul style="text-align: left;"><li><span style="font-family: courier;">EnableUpdateHelpDefaultSourcePath - </span>This entry enables the policy. It is of type <b>dword </b>and has a value of 1 to indicate that the policy is applied.</li><li><span style="font-family: courier;">DefaultSourcePath -</span>This parameter defines the location to be used as the default source path and is of type <b>String</b>. You would probably use a network share. Irrespective, you should note that in this string you must escape any back slash character with aqn additional backslash. If the default source path is <b>\\dc1\help</b>, you see it as <b>"\\\\dc1\\help"</b>.</li></ul></div></div><div><br /></div><h3 style="text-align: left;">Using Windows PowerShell Settings</h3></div><div>As I mentioned above, you can set a policy for PowerShell 7 use but use whatever values you set for Windows PowerShell policy. In most or at least many cases, if you have Windows PowerShell policies set, you probably want the same policies set for PowerShell usage as well.</div><div><br /></div><div>To set any of the 6 polices to apply to PowerShell 7, but using the Windows PowerShell session you set two value entries in the six polices review above. The first is the Enable value entry, which enables that policy. Then you add another value entry:</div><div><ul style="text-align: left;"><li><b><span style="font-family: courier;">UseWindowsPowerShellPolicySetting </span></b>- This value entry indicates that the policy details should come from Windows PowerShell policies. It is of type <b>dword </b>and has a value of 1.</li></ul><div><br /></div></div><h3 style="text-align: left;"><b>Summary</b></h3><div>We looked at the six policies you can set and which registry key and value entries used by each policy. In the next article, I show you how to use the Group Policy cmdlets and PowerShell 7 to create and deploy these policies.</div></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-82268681398821529392021-12-09T16:34:00.006+00:002021-12-09T16:37:42.871+00:00Viewing PowerShell Files in Preview within WIndows Explorer<p>Windows Explorer has a nice feature that shows the contents of a selected file. Click on a file and in the right pane you can see the contents. This is a great feature, except it does not work for ALL filetypes out of the box. So would you wish to view a .PS1 file this way - you are out of luck. By default</p><p>By default, the preview pane is disabled. So you must first enable it. With the latest versions of Windows 11, it looks like this:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj24RR-z_UEJ51qUF8TriaczJhkYkESitujOYtrUBbp6og0dvsSfnG4bvXIQKEL5NBmbxA6SBpkR9CYENT2VkafhBMScVygCebqodbiZ02E2y25Zrifc8cUHoKQI94f_C5bR6osw/s1408/2021-12-09_16-20-09.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="694" data-original-width="1408" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj24RR-z_UEJ51qUF8TriaczJhkYkESitujOYtrUBbp6og0dvsSfnG4bvXIQKEL5NBmbxA6SBpkR9CYENT2VkafhBMScVygCebqodbiZ02E2y25Zrifc8cUHoKQI94f_C5bR6osw/w400-h198/2021-12-09_16-20-09.png" width="400" /></a></div><br /><p>But even after enabling this, you still can not view .PS1 files (or .PSM1 or .PSD1 files either) in the preview pane within Explorer. </p><p>But like just about every default - with PowerShell there is usually a way to override it. And it turns out to make these files visible in the preview pane, you just need to run the following script:</p><p><span style="color: #0b5394; font-family: courier;"><b># Define paths<br /></b></span><b style="color: #0b5394; font-family: courier;">$Path1 = 'Registry::HKEY_CLASSES_ROOT\.ps1'<br /></b><b style="color: #0b5394; font-family: courier;">$Path2 = 'Registry::HKEY_CLASSES_ROOT\.psm1'<br /></b><b style="color: #0b5394; font-family: courier;">$Path3 = 'Registry::HKEY_CLASSES_ROOT\.psd1'</b></p><p><span style="color: #0b5394; font-family: courier;"><b># Set registry values to enable preview<br /></b></span><b style="color: #0b5394; font-family: courier;">New-ItemProperty -Path $Path1 -Name PerceivedType -PropertyType String -Value 'text'<br /></b><b style="color: #0b5394; font-family: courier;">New-ItemProperty -Path $Path2 -Name PerceivedType -PropertyType String -Value 'text'<br /></b><b style="color: #0b5394; font-family: courier;">New-ItemProperty -Path $Path3 -Name PerceivedType -PropertyType String -Value 'text'</b></p><p>That's it. Once you run the script, you see things like this:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpq4a1avLltNYXPHHea-Am08R8raSoWdwVemZBPbzxys2wdiS47zVXp7iNYl7Lgh5TVxJvb-2NdDNUYrVOBMGokq3LgIC8QL39eOmuj560F3qlmycCHDYWGFwa2ce1PgCvaZF6wg/s1406/2021-12-09_16-32-34.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="515" data-original-width="1406" height="234" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpq4a1avLltNYXPHHea-Am08R8raSoWdwVemZBPbzxys2wdiS47zVXp7iNYl7Lgh5TVxJvb-2NdDNUYrVOBMGokq3LgIC8QL39eOmuj560F3qlmycCHDYWGFwa2ce1PgCvaZF6wg/w640-h234/2021-12-09_16-32-34.png" width="640" /></a></div><br /><p>Another mystery solved</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-110434536835473252021-10-25T14:03:00.000+01:002021-10-25T14:03:02.868+01:00Saving PowerPoint Deck as a PDF - with PowerShell 7<p> This week, I got into a twitter discussion about a presenter posting their slides for delegates. My personal preference is to always share the slides. Often, especially when I was working for an employer, I'd share a PDF of the file rather than the slides. Some decks had had a LOT of effort put in (some by inhouse graphics guys) and giving those animations away was sub-optimal for IP reasons. </p><p>My approach was to post whatever material was appropriate to a DropBox share - and let people have that. I created a unique Bit.Ly short URL, and put that on the first few and final slides. Since the shortend URL never changed, I could put whatever content was relevant - letting attendees know this would all disappear in a few week's time.</p><p>What I used to do was to run a short little PowerShell script, during the final development of the deck. If, like SO many presenters, I made a change in the speaker's lounge just before going on - I could run the script just before unplugging and heading to the talk. I could just share https://bit.ly/TFLPresentations and manage the content.</p><p>Converting your PowerPoint deck to a PDF is straightforward - I blogged about <a href="https://www.blogger.com/blog/post/edit/5384857/7329981491955980368" target="_blank">how to convert a Powerpoint deck into a PDF using PowerShell</a> a long time ago. The script uses the PowerPoint objects that are part of Office and which Office setup conveniently stores in the .NET Framework's Global Assembly Cache (the GAC). </p><p>After the Twitter conversation, I dusted off this script and to my surprise, it did not work. And the reason is that PowerShell 7 uses .NET and not The .NET Framework. The former does not make use of the GAC, so when I tried to load the appropriate assembly I got this error:</p><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><p><b><span style="font-family: courier;">PS C:\Foo> Add-Type -AssemblyName microsoft.office.interop.powerpoint</span></b></p></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><p><b><span style="color: red; font-family: courier;">Add-Type: Cannot find path 'C:\Foo\microsoft.office.interop.powerpoint.dll' because it does not exist.</span></b></p></blockquote><p>After a few minutes contemplation I realised what the issue was. And by using Void Tools most excellent SearchEvereything product, I found the assembly at the snappy location of: <span style="font-family: courier;">C:\Windows\assembly\GAC_MSIL\Microsoft.Office.Interop.PowerPoint\15.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.PowerPoint.dll</span>.</p><p>So now I know the location, I could do this to save a single file:</p><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div><span style="color: green;"><span style="font-size: x-small;"># Define the files</span></span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div><span style="font-size: x-small;">$PPTFile = <span style="color: #a31515;">'C:\foo\test.pptx'</span></span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div><span style="font-size: x-small;">$PDFFile = <span style="color: #a31515;">'D:\Dropbox\AAA-TFL Presententations LIVE\test.pdf'</span></span></div></div></blockquote><blockquote style="border: none; margin: 0 0 0 40px; padding: 0px;"><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; text-align: left; white-space: pre;"><span style="font-size: x-small;"> </span></div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="color: green;"><span style="font-size: x-small;"># Add the DLL</span></span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="font-size: x-small;">$DLLFile = <span style="color: #a31515;">'C:\Windows\assembly\GAC_MSIL\Microsoft.Office.Interop.PowerPoint\'</span> +</span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="font-size: x-small;"> <span style="color: #a31515;">'15.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.PowerPoint.dll'</span></span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="color: green;"><span style="font-size: x-small;"># Add the type</span></span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="font-size: x-small;">Add-Type -Path $DLLFile</span></div></div></blockquote><blockquote style="border: none; margin: 0 0 0 40px; padding: 0px;"><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; text-align: left; white-space: pre;"><span style="font-size: x-small;"> </span></div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="color: green;"><span style="font-size: x-small;"># Create save as PDF option</span></span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="font-size: x-small;">$SaveOption = [<span style="color: blue;">Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType</span>]::ppSaveAsPDF</span></div></div></blockquote><blockquote style="border: none; margin: 0 0 0 40px; padding: 0px;"><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; text-align: left; white-space: pre;"><span style="font-size: x-small;"> </span></div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="color: green;"><span style="font-size: x-small;"># Open the PowerPoint Presentation</span></span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="font-size: x-small;">$PPT = New-Object -ComObject <span style="color: #a31515;">"PowerPoint.Application"</span></span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="font-size: x-small;">$Presentation = $PPT.Presentations.Open($PPTFile)</span></div></div></blockquote><blockquote style="border: none; margin: 0 0 0 40px; padding: 0px;"><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; text-align: left; white-space: pre;"><span style="font-size: x-small;"> </span></div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="color: green;"><span style="font-size: x-small;"># Save it as a PDF and close the presentation</span></span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="font-size: x-small;">$Presentation.SaveAs($PdfFile,$SaveOption)</span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="font-size: x-small;">$Presentation.Close()</span></div></div></blockquote><blockquote style="border: none; margin: 0 0 0 40px; padding: 0px;"><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; text-align: left; white-space: pre;"><span style="font-size: x-small;"> </span></div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="color: green;"><span style="font-size: x-small;"># Close PPT and kill the process to be sure</span></span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="font-size: x-small;">$PPT.Quit()</span></div></div><div style="background-color: white; font-family: "Cascadia Code", Consolas, "Courier New", Consolas, "Courier New", monospace; line-height: 19px; white-space: pre;"><div style="text-align: left;"><span style="font-size: x-small;">Get-Process <span style="color: #a31515;">'POWERPNT'</span> | Stop-Process</span></div></div></blockquote><p>This fragment adds in the necessary DLL, opens the presentation from wherever I have it stored today, and then saves the file as PDF into the DropBox folder. </p><p>I kind of thought that the <b><span style="font-family: courier;">Quit()</span></b> method would kill PowerPoint but in my testing, the process hung around hence killing the process at the end of the fragment. Depending on how adventurous you wish to be, you can always wrap this code to get all the PPT files in one folder and save them away. </p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-88434450640652584532021-10-19T16:42:00.005+01:002021-10-19T17:52:02.295+01:00Patching and PowerShell 7<p> Many of you reading that blog know I'm a big supporter of PowerShell 7. I hope that many of you share my enthusiasm. After writing several books on PowerShell, and two on PowerShell 7, I find it a pretty good product.</p><p>One of the challenges which PowerShell brings to the enterprise is updates. Like most software products, there are bugs and vulnerabilities in PowerShell. I was reminded again of this fact reading an article from my <a href="https://paper.li/doctordns/1580827252" target="_blank">Powershell Paper.Li paper</a>. Today the top article comes from Bleeping Computer: <a href="https://www.bleepingcomputer.com/news/microsoft/microsoft-asks-admins-to-patch-powershell-to-fix-wdac-bypass/">https://www.bleepingcomputer.com/news/microsoft/microsoft-asks-admins-to-patch-powershell-to-fix-wdac-bypass/</a>.</p><p>The team do a great job in updating the code as soon as the vulnerabilities are found. In some (many) cases, the issue is not in PowerShell itself, but in one of the components, such as .NET. Once the team releases an update, you need to ensure that the update is rolled out everywhere you use PowerShell 7.</p><p>The method you use to keep PowerShell 7 up to date depends on how you installed PowerShell 7 in the first place. And here you have (at least) 3 options:</p><p></p><ul style="text-align: left;"><li>Use<span style="font-family: courier;"> Install-PowerShell.ps1</span> - this is a script you download from GitHub which enables you to install the latest production version of PowerShell, the latest next version Preview and (for the very brave) today's daily builds. If you use this, then you must manually update the software yourself. I love this as I am in control!</li><li>Use the Microsoft store - you get <a href="https://www.microsoft.com/en-us/p/powershell/9mz1snwt0n5d?activetab=pivot:overviewtab" target="_blank">the released version directly from the store</a>. This should automatically keep your version up to date as the PowerShell team. At present, there is no Store application for Windows Server. You can also <a href="https://www.microsoft.com/en-us/p/powershell-preview/9p95zzktnrn4?activetab=pivot:overviewtab" target="_blank">get the Preview version from the store</a> (although I do not know how that plays if you also have the released version installed). </li><li>Use a third-party repository - you could <a href="https://github.com/PowerShell/PowerShell/releases/" target="_blank">download PowerShell directly from Github</a> and install it (and manually update it as new versions get pushed out). You can also use Chocolatey although technically that is not supported.</li></ul><div>So you have options. Personally, I update the daily build once or twice a week and update the preview and production versions once I get a warning about an updated version the next time I start PowerShell. </div><div><br /></div><div>So no matter how you install PowerShell 7, make sure you have a patch strategy in place. And if you have read this far, make sure you have installed 7.1.5 (or 7.0.8 if you are still on 7.0).</div><div><br /></div><p></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-70887146572118165062021-08-08T16:42:00.003+01:002021-08-08T19:34:25.813+01:00A Great Book On Windows Terminal <p> </p><h1><span lang="EN-GB">Review of Will Fuqua’s book “Windows Terminal Tips, Tricks,
and Productivity Hacks”<o:p></o:p></span></h1>
<p class="MsoNormal"><span lang="EN-GB"></span></p><div class="separator" style="clear: both; text-align: center;"><span lang="EN-GB"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfon-buY1pywo_DsrJzC6N2RF00UwNiwDulRXVCHt8-eEUFj6cBm-CXCoEQ6A_wnKW9cK2RjSkYQEjuFgh_3Lm_2ny5POkrmLWP9bCA10MKk3tIYe_lWVBlxqvcati7vzMF6eoEg/s2048/file.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2048" data-original-width="1661" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfon-buY1pywo_DsrJzC6N2RF00UwNiwDulRXVCHt8-eEUFj6cBm-CXCoEQ6A_wnKW9cK2RjSkYQEjuFgh_3Lm_2ny5POkrmLWP9bCA10MKk3tIYe_lWVBlxqvcati7vzMF6eoEg/w325-h400/file.jpeg" width="325" /></a></span></div><span lang="EN-GB"><br /> </span><p></p><p class="MsoNormal">I have had the pleasure of reading through this
recently published book (<a href="https://smile.amazon.com/Windows-Terminal-Tricks-Productivity-Hacks-ebook/dp/B08XK8C5FD/ref=smi_www_rco2_go_smi_4368549507?_encoding=UTF8&%2AVersion%2A=1&%2Aentries%2A=0&ie=UTF8" target="_blank">Smile.Amazon.Com</a>).
This is a timely book, full of tips and tricks for using the new Windows Terminal.</p>
<p class="MsoNormal"><span lang="EN-GB">Ever since Microsoft got into the OS
business, we’ve had a console or shell built into the OS. The earliest, command.com,
gave way to cmd.exe with NT 3.1. And later came Windows PowerShell, the
PowerShell ISE and of course PowerShell 7 with VS Code. And now we have Windows
Terminal. <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">As the book clarifies, there really are two
components at work when you use tools like PowerShell. The first is the <b><i>shell</i></b>,
with the second being the <b><i>terminal</i></b>. As the book makes clear, the
terminal is, essentially, “what you see” when you use a command-line tool. The
terminal renders any text, draws any UI, and accepts kb/mouse input. The
terminal sends input to the shell for the actual processing. The shell then processes
the input and returns the results back to the terminal to display. <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">When you use cmd.exe or PowerShell, conhost.exe
is the terminal with the command prompt or Windows Powershell/PowerShell 7 as
the shell. The actual shell does not
have a UI as such – it gets input from and sends output to the terminal. It is
important to separate the two.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">Conhost.exe is really pretty primitive – it
works and does the job but could do so much more. Which is a thought that has
led to the development of a new, open-source, cross-platform terminal
supporting just about any shell, including the shells in Linux distributions
you can run under the Windows Subsystem for Linux (WSL2). The new windows terminal is not just a re-write
of conhost.exe, but is so much more! <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">As a PowerShell user, I traditionally used PowerShell
via either the command line (i.e. pwsh.exe, cmd.exe, powershell.exe) or most
often via VS Code (and some ISE). The
tool I chose at any given time reflected what I was about to do. I use a GUI to
develop and test scripts. And sometimes to run code. On the other hand, when I only
need to run code ( for example, my Get-TodayInHistory.ps1 script (https://github.com/doctordns/GDScripts/blob/main/Get-TodayInHistory.ps1)
that helps me pick music to play today), I chose the console as my terminal. <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">The book begins with a look at both what
the terminal is and how you install it, followed by a great chapter on the UI.
If you are going to be using the new terminal, Chapter 2 has several important
key sequences you need to work into your muscle memory. <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">In the second section, the book looks at
how you can configure Windows Terminal and the shells you use. The book
contains lots of great tips for using the terminal and PowerShell and WSL2 Ubuntu
via Windows Terminal. <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">For the hardcore developer, the final
section in the book looks at how you can use Windows Terminal in development.
The book looks at using GIT and GitHub and building web applications (with
React) and REST APIs. The book finishes
with a look at connecting to a remote host and managing hosts in the cloud by using
Azure Cloud Shell or Google Cloud shell in the Windows Terminal.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">If you are a casual terminal user, Windows
Terminal does everything you used to use consoles for – and a lot more. Windows
Terminal is a great tool if you are a WSL2 user, perhaps creating APIs or web
apps. For both audiences (and everyone in between), this book provides great
guidance, tips/tricks, and best practices.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>
<p class="MsoNormal"><span lang="EN-GB"> </span></p>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-5384857.post-85054440465776364422021-06-21T20:17:00.004+01:002021-06-21T20:19:32.040+01:00My Next Book is Announced! <div class="separator" style="clear: both; text-align: center;"><a href="https://images-na.ssl-images-amazon.com/images/I/41Ac1ALxIQS._SX403_BO1,204,203,200_.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="500" data-original-width="405" src="https://images-na.ssl-images-amazon.com/images/I/41Ac1ALxIQS._SX403_BO1,204,203,200_.jpg" /></a></div><br /><p>I am pleased that my publisher, Packt, have announced my next book on PowerShell. The new book is entitled <b><i>Windows Server Automation with PowerShell Cookbook</i></b> and it should be released in July.</p><p>You can pre-order it from Amazon - <a href="https://smile.amazon.co.uk/Windows-Server-Automation-PowerShell-Cookbook-ebook/dp/B0977JDL7K/ref=sr_1_1?dchild=1&keywords=Windows+Server+Automation+with+PowerShell+Cookbook+-+Fourth+Edition&qid=1624277697&s=books&sr=1-1" rel="" target="_blank">in the UK, use the Smile.Amazon.Co.UK site</a>. In the US, <a href="https://smile.amazon.com/Windows-Server-Automation-PowerShell-Cookbook-ebook/dp/B0977JDL7K/ref=sr_1_1?dchild=1&keywords=Windows+Server+Automation+with+PowerShell+Cookbook+-+Fourth+Edition&qid=1624277697&s=books&sr=1-1" target="_blank">use the Smile.Amazon.Com site</a>. </p><p>I am looking for a few good books reviewers - you get a copy of the book in exchange for a review. If you are interested, send me some email at DoctorDNS@Gmail.Com.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-65992994323929395502021-06-01T15:26:00.001+01:002021-06-01T15:26:10.077+01:00Resolving Hyper-V issues with WIn10 Insiders builds<p> I have been a member of the <a href="https://insider.windows.com/" rel="nofollow" target="_blank">Windows Insiders group</a> since 2014, and have enjoyed testing out the updates and looking at some of the new features coming to a new Win10 release in due course. A very few Insiders builds were bad - and just did not work. But that was rare and for the most part, the new builds work well.</p><p>I recently encountered an issue whereby after the upgrade, no Hyper-V VM would start. The error log shows an error message about MCompute faults - which looks like this in the event log.</p><p><span style="color: #741b47; font-family: courier;"></span></p><blockquote><p><span style="color: #741b47; font-family: courier;"><b>Faulting application name: vmcompute.exe, version: 10.0.21354.1, time stamp: 0x1aa49b37</b></span></p><p><span style="color: #741b47; font-family: courier;"><b>Faulting module name: vmcompute.exe, version: 10.0.21354.1, time stamp: 0x1aa49b37</b></span></p><p><span style="color: #741b47; font-family: courier;"><b>Exception code: 0xc0000005</b></span></p><p><span style="color: #741b47; font-family: courier;"><b>Fault offset: 0x00000000001c065a</b></span></p><p><span style="color: #741b47; font-family: courier;"><b>Faulting process ID: 0x23a8</b></span></p><p><span style="color: #741b47; font-family: courier;"><b>Faulting application start time: 0x01d72d3e4d15903d</b></span></p><p><span style="color: #741b47; font-family: courier;"><b>Faulting application path: C:\WINDOWS\system32\vmcompute.exe</b></span></p><p><span style="color: #741b47; font-family: courier;"><b>Faulting module path: C:\WINDOWS\system32\vmcompute.exe</b></span></p><p><span style="color: #741b47; font-family: courier;"><b>Report ID: f8375064-c2fc-4a89-a8f1-af662c551008</b></span></p><p><span style="color: #741b47; font-family: courier;"><b>Faulting package full name: </b></span></p><p><span style="color: #741b47; font-family: courier;"><b>Faulting package-relative application ID:</b></span></p></blockquote><p>I reported this error multiple times, but to no avail. Every week, Windows Update would offer a new build that would fail to restart Hyper-V.. I'd revert to a working build, report the issue - then wait a week and repeat. Despite multiple reports, I never got any response from MSFT. </p><p>I decided to take a near-nuclear option - which worked! In hopes that someone else who encounters this issue and, using their search engine, finds this post - here is my solution:</p><p></p><ol style="text-align: left;"><li>Start, then shut down all VMs.</li><li>Took an inventory of the VMs.</li><li>Remove all the un-needed VM snapshots - there were too many and all are now gone! </li><li>Export all the VMs to a backup drive (removing the snapshots helped reduce the time).</li><li>Remove the Windows 10 Hyper-V feature - all of it.</li><li>Reboot.</li><li>Accept the latest Insiders update and let it install.</li><li>Once the upgrade is complete, add the Hyper-V feature back in.</li><li>Reboot.</li><li>Open up the Hyper-V console and install the necessary VM switches (two in my case).</li><li>Import the VMs specifying the location on the VM location on the host's disk of the VM (and not the backup!).</li><li>For some VMs< i need to specify where the virtual hard disks were stored (I use a non-standard location).</li><li>Start the VMs and enjoy.</li></ol><div>Here is what I see now!</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgm92UskwcFPREoOtP76lng_38mr_Uvi941kBJfq1MOV2mxZYU3Irn52UUihankUzi2776vs_mlateULjXfqeoob8awahfxU6IImGLOquhD41NTn1aRohqErbzEi_efBzhGUBbUew/s1026/2021-05-29_11-03-37.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="432" data-original-width="1026" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgm92UskwcFPREoOtP76lng_38mr_Uvi941kBJfq1MOV2mxZYU3Irn52UUihankUzi2776vs_mlateULjXfqeoob8awahfxU6IImGLOquhD41NTn1aRohqErbzEi_efBzhGUBbUew/w603-h254/2021-05-29_11-03-37.png" width="603" /></a></div><br /><div><br /></div><div><br /></div><div>Once you are up and running, make sure to remove the backups.</div><div><br /></div><div>From start to finish, it took me a couple of days elapsed time (the backup to an external USB2 drive was slow!). </div><div><br /></div><div>In step 2, I took inventory (including identifying the snapshots and working out how much data had to be backed up. One useful step wasn running this query and saving the output. </div><div><div><span style="color: #741b47; font-family: courier;"><b></b></span></div><blockquote><div><span style="color: #741b47; font-family: courier;"><b>PS C:\Foo> Get-VM | Format-Table -Property Name, Path</b></span></div><div><span style="color: #741b47; font-family: courier;"><b><br /></b></span></div><div><span style="color: #741b47; font-family: courier;"><b>Name Path</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>---- ----</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>***Cookham1 D:\VMs\Cookham1</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>CH1 D:\V8\CH1</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>DC1 d:\v8\DC1</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>DC2 d:\v8\DC2</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>HV1 D:\V8\HV1</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>HV2 d:\v8\HV2</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>Hyper-V Server D:\V7\HyperVServer\Hyper-V Server</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>Old - Bridge D:\V7\Bridge</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>PSRV D:\V8\PSRV</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>SMTP-2019 D:\V8\SMTP-2019\SMTP-2019</b></span></div><div><span style="color: #741b47; font-family: courier;"><b>SRV1 D:\V8\SRV1</b></span></div><b style="color: #741b47; font-family: courier;">SRV2 D:\V8\SRV2</b><div><span style="color: #741b47; font-family: courier;"><b>SS1 D:\V8\SS1</b></span></div></blockquote><p>After all the updating, in step 11, I pointed the MMC's import wizard at the path noted above and most of the VMs came in fine. For the "V8" VMs, I had to specify the same path to let the wizard know where each of the disks was stored. </p><p>Hope you never encounter this issue but if you do the is a workaround. </p><p><br /></p><p><br /></p></div><div><br /></div><div><br /></div><div><br /></div><p></p><p><br /></p><p><br /></p><p><span style="color: #741b47; font-family: courier;"></span></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-69300689455720919122021-01-11T11:01:00.002+00:002021-01-11T11:01:42.694+00:00Packt Publishers Sale on Through Jan 13 2021<p><span style="font-family: verdana;">In my morning email was a message from the publishers of two (and soon three) books. My books are on PowerShell, but as many of you know, they publish books, ebooks, and videos across the IT Spectrum. In my experience, some of their books are better than others. I'd like to think that some books, including mine, are in the 'good' category - but as ever Caveat Emptor.</span></p><p><span style="font-family: verdana;">Their reason for writing to me is that they currently have a sale on at the moment. This sale, which is on through Jan 13th 2021 offers certain WIndows/Linux books and ebooks for sale. </span></p><p><span style="font-family: verdana;">I apologise for the short notice, but I only heard about this from a mail I got this morning.</span></p><p><span style="font-family: verdana;"><b>Mastering Windows Server 2019</b> - <a href="https://www.packtpub.com/product/mastering-windows-server-2019-second-edition/9781789804539?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators">https://www.packtpub.com/product/mastering-windows-server-2019-second-edition/9781789804539?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators</a></span></p><p><span style="font-family: verdana;"><b>Mastering Windows Security and Hardening</b> - <a href="https://www.packtpub.com/product/mastering-windows-security-and-hardening/9781839216411?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators">https://www.packtpub.com/product/mastering-windows-security-and-hardening/9781839216411?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators</a></span></p><p><b style="font-family: verdana;">Windows Server 2019 Administration fundamentals, Second Edition</b><span style="font-family: verdana;"> - <a href="https://www.packtpub.com/product/windows-server-2019-administration-fundamentals-second-edition/9781838550912?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators">https://www.packtpub.com/product/windows-server-2019-administration-fundamentals-second-edition/9781838550912?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators</a></span></p><p><span style="font-family: verdana;"><b>Mastering Linux Security and Hardening</b> - <a href="https://www.packtpub.com/product/mastering-linux-security-and-hardening-second-edition/9781838981778?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators">https://www.packtpub.com/product/mastering-linux-security-and-hardening-second-edition/9781838981778?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators</a></span></p><p><span style="font-family: verdana;"><b>Windows Subsystem for Linux 2 (WSL 2) Tips, Tricks, and Techniques</b> -<a href="https://www.packtpub.com/product/windows-subsystem-for-linux-2-wsl-2-tips-tricks-and-techniques/9781800562448?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators">https://www.packtpub.com/product/windows-subsystem-for-linux-2-wsl-2-tips-tricks-and-techniques/9781800562448?utm_source=4sysops&utm_medium=&utm_campaign=5dollar2020&utm_term=system-administrators</a></span></p><p><span style="font-family: verdana;">And what list of great books on offer would be incomplete without my latest book: </span></p><p><span style="font-family: verdana;"><b>Windows Server 2019 Automation with PowerShell Cookbook - Third Edition</b> -<a href="https://www.packtpub.com/product/windows-server-2019-automation-with-powershell-cookbook-third-edition/9781789808537">https://www.packtpub.com/product/windows-server-2019-automation-with-powershell-cookbook-third-edition/9781789808537</a></span></p><p><br /></p><p><span style="font-family: verdana;"><br /></span></p><p><span style="font-family: verdana;"><br /></span></p><p><span style="font-family: verdana;"><br /></span></p><p><span style="font-family: verdana;"><br /></span></p><p><br /></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-34898349986088007882021-01-10T13:23:00.001+00:002021-01-10T13:56:26.346+00:00My Wiley PowerShell Book - Issues with the code samples<p>I recently posted (<a href="https://tfl09.blogspot.com/2020/12/my-latest-powershell-book-copies.html">https://tfl09.blogspot.com/2020/12/my-latest-powershell-book-copies.html</a>) about my latest PowerShell book, published by <a href="https://www.wiley.com/en-gb/PowerShell+7+for+IT+Professionals-p-9781119644705">Wiley</a>. I am proud of this book for many reasons. Most of the writing was done after the start of the Covid pandemic. Frankly, the writing helped keep me sane (well saner). </p><p>Writing a book involves a lot of people. I write stuff and then a good team of others help to turn this into a finished product. In particular, I was very happy with the excellent editing done by the Wiley team. The development process was laborious and my editors were a pedantic nightmare - but all in the Best Possible Way! I appreciated the almost anal nitpicking done and the total focus on quality. Everyone involved has my gratitude for their excellent work.</p><p>But...</p><p>Today I received a mail from a wonderful reader in Italy. He complained that cutting and pasting from the e-book failed. He provided me with some examples. Yes, he is right that what he showed me is NOT what I wrote and submitted.</p><p>My apologies for this to him, and everyone reading my book. I can assure you that I did everything I could to avoid this very issue. Jim, my TE, was totally focused on helping me to avoid issues like this - every missing capital letter, every missing parameter name, and every other minor error was flagged and resolved. I did what I could, and am sorry for the resulting issues.</p><p>With that said, one of the things I insisted on was that I could publish these scripts on GitHub. You do not have to buy my book (although I hope you will) to use the scripts. You canfindt the scripts at GitHub account - <a href="https://github.com/doctordns/Wiley20">https://github.com/doctordns/Wiley20</a>.</p><p>So if you want to try out the book and the scripts contained in it, please do NOT cut/paste from an electronic version - use the scripts on Github. If you find errors there, PLEASE file an issue at https://github.com/doctordns/Wiley20/issues. I will do my best to fix anything that might be broken and republish the updated script. You are welcome to fork this repo and I'll accept PRs that fix errors in the scripts.</p><p>Thanks for everyone who either both my book or uses my scripts.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-69325655612597437002020-12-19T17:11:00.002+00:002020-12-19T17:11:14.747+00:00My Latest PowerShell Book - Copies Available<p> </p><div class="separator" style="clear: both; text-align: left;">After a long development process, my latest PowerShell book has been published by Wiley</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVG-QkaUcBaDeWXt8xeXcKif1baf6CUmE4Adg26R4JpTcooGRmE7h5QjpMLJjKlIR1D4EqeseeyneqDj8G_aIbV8l1pln4mqa_CaJ1qaeESi0uyWG_UFnfoRKwLYgCHHs6E1T1QA/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1594" data-original-width="1196" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVG-QkaUcBaDeWXt8xeXcKif1baf6CUmE4Adg26R4JpTcooGRmE7h5QjpMLJjKlIR1D4EqeseeyneqDj8G_aIbV8l1pln4mqa_CaJ1qaeESi0uyWG_UFnfoRKwLYgCHHs6E1T1QA/w300-h400/20201217_085316.jpg" width="300" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">This book began before the Covid pandemic began and progress as a result of the virus was a lot slower than I would have liked, but thanks to some great people we got it done and this week I got my review copies.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">As I announced on my Twitter (@DoctorDNS) feed, I have some copies of this book to give away. I am more than happy sign and send off copies of the physical book. I also want to find some reviewers and can provide them with an electronic copy for review if you contact me offline. </div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">I love the PowerShell community and nothing would please me more than to give a copy to anyone who asks. But that is not possible. So I am happy to give away some free copies, but to make it a bit more interesting, there is a little catch! :-)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"> I will give away <b>five</b> signed copies of the physical book to the first FIVE people who ask <b>and </b>who donate to the Epilepsy Society (https://epilepsysociety.org.uk/). My daughter has severe epilepsy and I support this charity. So to get a copy, confirm a donation and EMAIL me. My email addresses DoctorDNS@Gmail.Com.</div><div class="separator" style="clear: both; text-align: left;">. </div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b>[LATER]</b></div><div class="separator" style="clear: both; text-align: left;"><b>Owing to Covid restrictions announced today in the UK, physical copies may be delayed until I can get out to the Post Office. </b></div><br /><p></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-6478118423614424792020-12-11T10:14:00.000+00:002020-12-11T10:14:09.922+00:00How To: Change the File Time for a Windows FileWhen using PowerShell in Windows, The Get-ChildItem (and other cmdlets) return objects of the type System.IO.FileInfo for files in the NTFS File system. Each of the returned objects contains six date/time objects:<div><div><ul style="text-align: left;"><li><b>CreationTime</b> and <b>CreationTimeUtc</b> - the date/time that the file was created (in local time and UTC)</li><li><b>LastAccessTime</b> and <b>LastAccessTimeUtc</b> - the date/time that the file was last accessed</li><li><b>LastWriteTime</b> and <b>LastWriteTimeUtc</b> - the date/time that the file was last written</li></ul></div><div>These properties allow you to check a file (or for that matter a folder) for when it was created and when it was last written to and read from. This is very useful to help IT Professionals to discover files that are underused and may be candidates for deletion. To cater for files being accessed in different time zones, the UTC variants provide time-zone proof times for comparison.</div><div><br /></div><div>One challenge is that you may wish to change these times. There is no cmdlet that can change these times directly. Fortunately, there is a simple bit of PowerShell magic. Assume you have a file for which you wish to change date/times. </div><div><br /></div><div>Here is you can do it:</div><div><br /></div><div><div><span style="color: #741b47; font-family: courier;"></span></div><blockquote><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: Remove-Item -Path C:\Foo\Foo.xxx -ea 0 </span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: "FOO" | Out-File -Path C:\Foo\Foo.xxx</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: # Find file and display</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: $File = Get-ChildItem -Path c:\foo\Foo.xxx</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: $File| Format-List -Property name,*time*</span></div><div><span style="color: #741b47; font-family: courier;"><br /></span></div><div><span style="color: #741b47; font-family: courier;">Name : Foo.xxx</span></div><div><span style="color: #741b47; font-family: courier;">CreationTime : 11/12/2020 10:09:57</span></div><div><span style="color: #741b47; font-family: courier;">LastAccessTime : 11/12/2020 10:09:57</span></div><div><span style="color: #741b47; font-family: courier;">LastAccessTimeUtc : 11/12/2020 10:09:57</span></div><div><span style="color: #741b47; font-family: courier;">LastWriteTime : 11/12/2020 10:09:57</span></div><div><span style="color: #741b47; font-family: courier;">LastWriteTimeUtc : 11/12/2020 10:09:57</span></div><div><span style="color: #741b47; font-family: courier;"><br /></span></div><div><span style="color: #741b47; font-family: courier;"><br /></span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: # Get new date</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: $NewDate = Get-Date -Date '14/08/1950'</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: # Change the date</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: $File.CreationTime = $NewDate</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: $File.CreationTimeUTC = $NewDate</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: $File.LastAccessTime = $NewDate</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: $File.LastACcessTimeUTC = $NewDate</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: $File.LastWriteTime = $NewDate</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: $File.LastWriteTimeUTC = $NewDate</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: # Recheck file to see changed date/time</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: $File = Get-ChildItem -Path C:\Foo\Foo.xxx</span></div><div><span style="color: #741b47; font-family: courier;">PSH [C:\Foo]: $File| Format-List -Property Name,*Time*</span></div><div><span style="color: #741b47; font-family: courier;"><br /></span></div><div><span style="color: #741b47; font-family: courier;">Name : Foo.xxx</span></div><div><span style="color: #741b47; font-family: courier;">CreationTime : 14/08/1950 01:00:00</span></div><div><span style="color: #741b47; font-family: courier;">CreationTimeUtc : 14/08/1950 00:00:00</span></div><div><span style="color: #741b47; font-family: courier;">LastAccessTime : 14/08/1950 01:00:00</span></div><div><span style="color: #741b47; font-family: courier;">LastAccessTimeUtc : 14/08/1950 00:00:00</span></div><div><span style="color: #741b47; font-family: courier;">LastWriteTime : 14/08/1950 01:00:00</span></div><div><span style="color: #741b47; font-family: courier;">LastWriteTimeUtc : 14/08/1950 00:00:00</span></div></blockquote><div><span style="font-family: courier;"></span></div></div><div><br /></div></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-73499660944400230562020-11-26T18:09:00.007+00:002020-11-28T20:13:12.933+00:00Creating a PowerShell Cmdlet Using C# and DotNet.eXE<p>As part of a book I am writing, I wanted to show how simple it could be to create your own cmdlet in C#. This was to be a part of an advanced look at the things you can do with PowerShell 7 and DotNet Core. </p><p>Most IT professionals know about the .NET objects produced by cmdlets, how to discover details about those objects, and how to reach into the .NET BCLs to do things that cmdlets can't. You can also extend PowerShell using a .NET Language such as C# to create a class. You use <b>Add-Type</b> to import the class into your PowerShell session and use it just like any other .NET class. Creating a cmdlet turned out to be more complex.</p><p>The first question any sane person might ask is; WHY? Why would anyone want to write a cmdlet or create a class using C#? The obvious reason, per Jimmy The Swede, is because you can. As an IT professional, knowing how is just another tool on your tool belt. But aside from that, there really are some good reasons. Using C# is easier when you need to perform asynchronous operations or multi-threading, or if you wish to use Language-Integrated Query (LINQ). IN those cases, C# is a lot easier than trying to use PowerShell in those scenarios. Another use case is taking some ASP.NET code, such as a page which creates a list of out of stock items and re-purposing it for administrative use. Admittedly, there are not a <i>lot</i> of use cases in the wild - but as a PowerShell person, you should know!</p><p>If you are a hardcore Windows developer, you probably have Visual Studio and know how to use it. But in this article, I'm going to use a different approach which is to use the .NET SDK and the dotnet.exe command. You can do most of this from the command line, although there seems no simple way to install the SDK. So here goes</p><p>1. Install the .Net Core SDK. </p><p>This is almost the hardest part of the job. You need to install the Software Development Kit in order to get the tools you need to create the cmdlet. This involves using the GUI.</p><p>Navigate to the Dotnet download page: <span style="background-color: white; color: green; font-size: 14px; white-space: pre;">https://dotnet.microsoft.com/download/</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih2zzAogrUPD_pD6myLdGAKR2WK0N1DDn59-DSbsCqdupkb4d5nsKBQJsIZt8r-F0ZkjlCqc40Wq_TzPpiNZ05aT8ApJXnpUYFapQGAzUoc9UReRQZWDhqV_nvalPgBMatuGbLnw/s1511/1+Download+.NET.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="974" data-original-width="1511" height="413" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih2zzAogrUPD_pD6myLdGAKR2WK0N1DDn59-DSbsCqdupkb4d5nsKBQJsIZt8r-F0ZkjlCqc40Wq_TzPpiNZ05aT8ApJXnpUYFapQGAzUoc9UReRQZWDhqV_nvalPgBMatuGbLnw/w640-h413/1+Download+.NET.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">From here, click on the download button. This leads to the downloading page:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfQl3id3XO8jCtaULge3cHNToabsqW-_V_gffvgOH1jucihxSgpqllN-WGPOIGQQDSA8d42hCqVxAmvWlr3DdXE2PnV18fTbezEV6TGDKnixiAOrUyVIPfYKInIx4dypZONPbbgg/s1511/2..+Download+sdk+installer.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="974" data-original-width="1511" height="413" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfQl3id3XO8jCtaULge3cHNToabsqW-_V_gffvgOH1jucihxSgpqllN-WGPOIGQQDSA8d42hCqVxAmvWlr3DdXE2PnV18fTbezEV6TGDKnixiAOrUyVIPfYKInIx4dypZONPbbgg/w640-h413/2..+Download+sdk+installer.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">The download takes a few seconds/minutes to download. Eventually, you can see in the bottom left corner that the download is complete and you can now click on the open file as you can see here:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3tg9EY_kIM7NAfHXBJlMUFZvKNqqSALKQHsLkcz3KRF5K2_jAvEeifxH21v9Tco0EibfUk0J8y8qwfIdv1noLdNZ3hUYgIpix56xneUBtipD_jWWLpx4ijaLBuv_38uMX7Tvc3A/s267/3.+opening+the+file.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="62" data-original-width="267" height="93" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3tg9EY_kIM7NAfHXBJlMUFZvKNqqSALKQHsLkcz3KRF5K2_jAvEeifxH21v9Tco0EibfUk0J8y8qwfIdv1noLdNZ3hUYgIpix56xneUBtipD_jWWLpx4ijaLBuv_38uMX7Tvc3A/w400-h93/3.+opening+the+file.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div>Clicking on the open file link runs the installer to install the .NET Core SDK on your computer. Eventually, you see this:<p></p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5JQgyCfDfthJeujkTOG1tTJR-MSmGpw0B6YfNyMdim8R4noXZ91J6z0rJ_2-CknNG87-6nbK0ZVHVZ0HTzRAeQThnRh0ad8a5CSpTvH_x8fAhFvLyTbowIjfVvGnntN7MxAD31Q/s646/5.+Completing+the+installation.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="481" data-original-width="646" height="475" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5JQgyCfDfthJeujkTOG1tTJR-MSmGpw0B6YfNyMdim8R4noXZ91J6z0rJ_2-CknNG87-6nbK0ZVHVZ0HTzRAeQThnRh0ad8a5CSpTvH_x8fAhFvLyTbowIjfVvGnntN7MxAD31Q/w640-h475/5.+Completing+the+installation.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Click on Close and you now have the SDK loaded on your system. From here it's fairly simple - here's the script:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both;"><div style="background-color: white; font-size: 14px; line-height: 19px; white-space: pre;"><div><span style="color: green;"></span></div><blockquote><div><span style="color: #4c1130; font-family: courier;"><b># 2. Create the cmdlet folder</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>New-Item -Path C:\Foo\Cmdlet -ItemType Directory -Force</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>Set-Location C:\Foo\Cmdlet</b></span></div><span style="color: #4c1130; font-family: courier;"><b><br /></b></span><div><span style="color: #4c1130; font-family: courier;"><b># 3. Creating a class library project</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>dotnet new classlib --name SendGreetings</b></span></div><span style="color: #4c1130; font-family: courier;"><b><br /></b></span><div><span style="color: #4c1130; font-family: courier;"><b># 4. Viewing contents of new folder</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>Set-Location -Path .\SendGreetings</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>Get-ChildItem</b></span></div><span style="color: #4c1130; font-family: courier;"><b><br /></b></span><div><span style="color: #4c1130; font-family: courier;"><b># 5. Creating global.json</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>dotnet new globaljson</b></span></div><span style="color: #4c1130; font-family: courier;"><b><br /></b></span><div><span style="color: #4c1130; font-family: courier;"><b># 6. Adding PowerShell package</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>dotnet add package PowerShellStandard.Library</b></span></div><span style="color: #4c1130; font-family: courier;"><b><br /></b></span><div><span style="color: #4c1130; font-family: courier;"><b># 7. Create the cmdlet source file</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>$Cmdlet = @"</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>using System.Management.Automation; // Windows PowerShell assembly.</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>namespace Reskit</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>{</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> // Declare the class as a cmdlet</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> // Specify verb and noun = Send-Greeting</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> [Cmdlet(VerbsCommunications.Send, "Greeting")]</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> public class SendGreetingCommand : PSCmdlet</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> {</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> // Declare the parameters for the cmdlet.</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> [Parameter(Mandatory=true)]</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> public string Name</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> {</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> get { return name; }</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> set { name = value; }</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> }</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> private string name;</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> // Override the ProcessRecord method to process the</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> // supplied name and write a geeting to the user by </b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> // calling the WriteObject method.</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> protected override void ProcessRecord()</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> {</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> WriteObject("Hello " + name + " - have a nice day!");</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> }</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b> }</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>}</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>"@</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>$Cmdlet | Out-File .\SendGreetingCommand.cs</b></span></div><span style="color: #4c1130; font-family: courier;"><b><br /></b></span><div><span style="color: #4c1130; font-family: courier;"><b># 8. remove class file </b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>Remove-Item -Path .\Class1.cs</b></span></div><span style="color: #4c1130; font-family: courier;"><b><br /></b></span><div><span style="color: #4c1130; font-family: courier;"><b># 9. Build the cmdlet</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>dotnet build </b></span></div><span style="color: #4c1130; font-family: courier;"><b><br /></b></span><div><span style="color: #4c1130; font-family: courier;"><b># 10. Importing the DLL holding the cmdlet</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>$DLLPath = '.\bin\Debug\net5.0\SendGreetings.dll'</b></span></div><div><span style="color: #4c1130; font-family: courier;"><b>Import-Module -Name $DLLPath</b></span></div></blockquote><div></div></div>at that point, you can use the Send-Greeting command, like this:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg55Idq65sJ4uO-NRDgjkbM8t-R8dx79VE1HmeEtmKAjyY05IDLEyOevFIIJQKl3yCrebfWtv92frpllU8UoJmITtIoCNYvW83HFZgJ_T6PFr3i9MgiELbTy-zFSfc6b8Oek8l3ow/s789/6.+USING+IT.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="210" data-original-width="789" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg55Idq65sJ4uO-NRDgjkbM8t-R8dx79VE1HmeEtmKAjyY05IDLEyOevFIIJQKl3yCrebfWtv92frpllU8UoJmITtIoCNYvW83HFZgJ_T6PFr3i9MgiELbTy-zFSfc6b8Oek8l3ow/w640-h170/6.+USING+IT.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: left;">Thanks to James O'Neil who got me started on this solution. Thanks also to Thomas Rayner's excellent PowerShell summit talk at <a href="https://www.youtube.com/watch?v=O0lk92W799g&t=4s">https://www.youtube.com/watch?v=O0lk92W799g&t=4s</a></div><p><br /></p><p><br /></p><div class="separator" style="clear: both; text-align: left;"><br /></div><br /><div class="separator" style="clear: both; text-align: left;"><br /></div><br /><span style="background-color: white; color: green; font-size: 14px; white-space: pre;"><br /></span><p></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-62649801765634330192020-11-12T16:49:00.002+00:002020-11-12T16:49:16.153+00:00PowerShell 7.1 ships. And it's in the Store<p> Yesterday, the PowerShell team announced that they had shipped PowerShell 7,1. This is the next version of the open-source, cross-platform version of PowerShell. This release is <i>not</i> a Long Term Support release, meaning support is limited. PowerShell 7.0 and the future 7,2 are LTS releases. The release was announced on <a href="https://devblogs.microsoft.com/powershell/announcing-powershell-7-1/">a blog post by Joey Aiello Program Manager, PowerShell</a>.</p><p>PowerShell 7.1 is focused on resolving community issues. You can read the release notes here: https://docs.microsoft.com/en-gb/powershell/scripting/whats-new/what-s-new-in-powershell-71?view=powershell-7.1/. While this is not an LTS release, the team have made some great strides forward in terms of the overall platform.</p><p>From an engineering point of view, the release of PowerShell moves to .NET 5.0. This major update to the .NET Core framework brings a lot of benefits for developers, including some performance improvements which you can read about at <a href="https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/">https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/</a>. You may find that in complex scripts, this translates to shorter run times. </p><div><br /></div><p>One thing which is noteworthy is that PowerShell is now in the Windows store:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVjrUVE7oOpTIwlDWdFMl7yoOEQaXxj4skWajKeh3BJXA0ehLd7hBcWN3sfH7zNrIUrqDJSs8KdAubuQ_uVcovLrGRMrkDU0D2jTktVe8lsuCtTdPOWGTKah4Jw16W8Zgd-VwBTg/s1791/2020-11-12_16-37-28.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="924" data-original-width="1791" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVjrUVE7oOpTIwlDWdFMl7yoOEQaXxj4skWajKeh3BJXA0ehLd7hBcWN3sfH7zNrIUrqDJSs8KdAubuQ_uVcovLrGRMrkDU0D2jTktVe8lsuCtTdPOWGTKah4Jw16W8Zgd-VwBTg/w640-h330/2020-11-12_16-37-28.png" width="640" /></a></div><p>And for the adventurous, a preview of 7.2 is meant to drop soon.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-28433924587335894552020-10-02T17:40:00.006+01:002020-10-02T17:40:35.847+01:00Open Sourcing of PowerShell Documents is AwesomeEver since the very first version of Windows PowerShell, the built-in help material has been awesome. Each cmdlet carefully documented with good examples to illustrate the most common use cases. Good English writing as well as best-practice PowerShell.<div><br /></div><div>But every now and then there is an error. Some simple, some more complex. Some occasionally have some less than great grammar or miss out a useful example of the cmdlet. In the old, old days, you could file an issue somewhere that no one ever seemed to read. And then wait a year or longer before the next version of Windows PowerShell. It used to drive me nuts. I did rant a bit at the time (sorry Erin).</div><div><br /></div><div>Then someone decided to Open Source the documentation and move it all to docs.microsoft.com. What a great idea. At first, it was a bit clumsy, as everyone involved slowly moved into the wonders of managing a complex repository at GitHub. The process was, again at first, a tad convoluted and frankly slow. BUT it worked. </div><div><br /></div><div>I recall the first time I saw an error. It was in class at Lab Center in Sweden. I was showing the delegates how to read the help text. A cmdlet parameters description said it did not take wild cards, but it did. Sok, in class, I filed an issue, edited the document, and issued a pull request. It was really cool although it took weeks to action.</div><div><br /></div><div>Today, I saw an issue that arrived in my email in basket. You can read the issue on https://github.com/MicrosoftDocs/PowerShell-Docs/issues/6697. That message hit my email box at 7.23 this morning. I read it just after 10/ A few minutes later, I had edited the document and created a pull request. A 13:30 or thereabouts, I got an email to say that the issue was now closed as the PR had been accepted. </div><div><br /></div><div>So 6 hours from the time I got the email till the issue was resolved. It is going to take a few more days for the update to hit the web site, but I can live with that. </div><div><br /></div><div>TL;DR to me is that with the open sourcing of PowerShell documentation, errors need not persist. You can fix them easily. Or just report and let the community do the work. </div>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-5384857.post-80200930157701153452020-05-11T11:28:00.004+01:002020-05-11T11:53:38.071+01:00Draw.IO Integration with VS Code <div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
Over the weekend, I saw a tweet announcing a new extension for VS Code. The extension "Draw.IO Integration "enables you to create good looking diagrams directly inside VS Code. Insane, I thought, then I downloaded it. I think a youthful view is that this is DOPE!<br />
<br />
You install the extension directly from inside VS Code, create and open a new *.Drawio document and away you go. If you have used virtually any diagramming tool, the interface is immediately accessible.<br />
<br />
Here is a screenshot of it working on my workstation:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggRwuj5EkyJFPrJM_r2bZg49e89a6nFUP2cQqKhqbflPI65CfVvpXwEIQP8mFroqQ5Yvbhfk6O9ZwbW5wbLo7Eth-EzVklT40JhzmAxKd4TaQqpc7w4YilNJXBaugR1aNBj3LSew/s1600/2020-05-11_11-08-40.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1072" data-original-width="1600" height="428" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggRwuj5EkyJFPrJM_r2bZg49e89a6nFUP2cQqKhqbflPI65CfVvpXwEIQP8mFroqQ5Yvbhfk6O9ZwbW5wbLo7Eth-EzVklT40JhzmAxKd4TaQqpc7w4YilNJXBaugR1aNBj3LSew/s640/2020-05-11_11-08-40.png" width="640" /></a></div>
<br />
As you can see, VS Code, up and running with my main workspace loaded and there in the module is a diagram too. It feels a LOT like Visio without (at least so far) the flakiness of Visio of late. The diagrams are not the nice polished ones you might be able to create using tools like PowerPoint, Visio, etc. But simple and BUILT-In. <br />
<br />
When you are finished with the diagram, you can export it in various formats. The diagram above, rendered to PNG, looks like this;<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqemp5dXQY4yUvAv_SSXRJ8BD0SbxGAvrJfxvYvmU-3Ow321ZYlW60NoRdqYnvfJiH5Us2fYKKut2FOznAmyqIQI7cXCLu0OBlqPLouG0LcS5bgAftRCqEZN3HVvXsbO1zeDodlQ/s1600/Untitled+Diagram.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="232" data-original-width="421" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqemp5dXQY4yUvAv_SSXRJ8BD0SbxGAvrJfxvYvmU-3Ow321ZYlW60NoRdqYnvfJiH5Us2fYKKut2FOznAmyqIQI7cXCLu0OBlqPLouG0LcS5bgAftRCqEZN3HVvXsbO1zeDodlQ/s640/Untitled+Diagram.png" width="640" /></a></div>
<br />
There are many templates and, I'm sure, every possibility of more being added by the community over time.<br />
<br />
<br />
<br /></div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-28189301070693200202020-04-01T14:36:00.002+01:002020-04-01T19:42:22.106+01:00Setting up an SMTP Relay using SendGrid<div dir="ltr" style="text-align: left;" trbidi="on">
<span style="font-family: "trebuchet ms" , sans-serif;">I have written several books - some of which have made use of SMTP to send mail. I am currently working on a Storage <a href="https://smile.amazon.co.uk/PowerShell-7-Pros-Thomas-Lee/dp/1119644720" target="_blank">chapter for my next book</a>. This chapter makes use of File Services Resource Manager (FSRM) to manage file storage. One neat feature of FSRM is its ability to send an email when events occur.</span><br />
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">For many, the issue of how to test this has been a challenge, especially if you do not have a happy SMTP server you can use. A neat tool I have used is to use IIS and the SMTP email relay service offered by SendGrid. You can read more about the company here: <a href="https://sendgrid.com/">https://sendgrid.com/</a></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">Setting up both IIS and the email relay service which SendGrid provides are straightforward to set up. In this blog post, I'll show you how to do this. </span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">There are 4 simple steps:</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">1. <b>Setup a SendGrid account</b> Ttheir free service allows you to send 100 emails a day, which should be more than enough for testing.</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">2. <b>Create a SendGrid API key</b> The API key is, in essence, your user id and password for the site (so be careful). Make sure you copy/paste the key carefully!</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">3. <b>Install IIS and configure an email relay using your SendGrid account</b> The GUI is pretty easy to use. There's probably a way using PowerShell, but I've not worked it out yet.</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">4. <b>Testing your relay</b> And for that, there IS a PowerShell script.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">Lets's look at these steps</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<div>
<b><span style="font-family: "verdana" , sans-serif;">Setup a SendGrid account</span></b></div>
<div>
<br /></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">The first step in creating your SMTP relay is to sign up for a (free) account with SendGrid. Like this</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">1. Navigate to SendGrid.Com (<a href="http://signup.sendgrid.com/">http://Signup.SendGrid.Com</a>) - </span><span style="font-family: "trebuchet ms" , sans-serif;">Use your browser to go to SendGrid's sign up page and fill out your details:</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8ly_JAkb5X289Bz7LPnDgu5LOni1HhZGK6XFgjepQOEECNI27MYKRHC-hpsctlXhPLs5bIeeF2-y_Y4cceAI87kN4RyMlNHJdV275SNotb4K6lFIbSlWt02UzJCWV_vAK45NR_Q/s1600/signup1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="766" data-original-width="724" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8ly_JAkb5X289Bz7LPnDgu5LOni1HhZGK6XFgjepQOEECNI27MYKRHC-hpsctlXhPLs5bIeeF2-y_Y4cceAI87kN4RyMlNHJdV275SNotb4K6lFIbSlWt02UzJCWV_vAK45NR_Q/s640/signup1.png" width="603" /></a></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">Make sure you create a very strong password. then click ok OK. </span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">2. This takes you to a page for your personal details Obviously, you should use your real name:</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcQ_drivVQejduSYV2T1Hqoi_h7mhbbNpVOgU1gH3uQELthS4KVqQdnr0sLBfLXSTwApa0Tr2SnOJ-aNJ_L5R3mN7NhJ8k5OpAGW419o2AXbVbE5QRS-ykrgQRm6gJMHkDEclYrA/s1600/signup2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="832" data-original-width="985" height="539" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcQ_drivVQejduSYV2T1Hqoi_h7mhbbNpVOgU1gH3uQELthS4KVqQdnr0sLBfLXSTwApa0Tr2SnOJ-aNJ_L5R3mN7NhJ8k5OpAGW419o2AXbVbE5QRS-ykrgQRm6gJMHkDEclYrA/s640/signup2.png" width="640" /></a></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;">Once you set these details, your account is setup. You should get email from SendGrid asking you to confirm your account. Please do NOT forget to do that.</span><br />
<b><span style="font-family: "verdana" , sans-serif;"><br /></span></b></div>
<div>
<b><span style="font-family: "verdana" , sans-serif;">Create a SendGrid API ke</span></b><span style="font-family: "trebuchet ms" , sans-serif;">y</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">3. Once you have created your SendGrid account, navigate to the Email Integration Guide from SendGrid's Home page:</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiM5P6_7Cpcghk-MBW2hSZMb3samSEK35lZ8b8GtAy5hMDImEz_Uzrs_pze_Bk0tBAwMdYBKl9hekURBlqMfLXRWApZsZJ7x00lJgG6ufzZnuQ_-FfZ45G1eXrTnhAVD5E8LAV4w/s1600/signup4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="511" data-original-width="225" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiM5P6_7Cpcghk-MBW2hSZMb3samSEK35lZ8b8GtAy5hMDImEz_Uzrs_pze_Bk0tBAwMdYBKl9hekURBlqMfLXRWApZsZJ7x00lJgG6ufzZnuQ_-FfZ45G1eXrTnhAVD5E8LAV4w/s320/signup4.png" width="140" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "trebuchet ms" , sans-serif;">4. This brings you to the configuration page, where you click to set up your SMTP relay:</span></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiyxcT-xLCxajF6vre7FO5eow7_121PxV1Og4LERSum2UnNGbBGT6_rLedhgJGAzpKeEjNibdKklnBc4oZ1w4lLJyJmeiWHheqPqrMpKb9H94pCqjsrssJhG5idHcOL13vN8nShw/s1600/signup5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="622" data-original-width="1128" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiyxcT-xLCxajF6vre7FO5eow7_121PxV1Og4LERSum2UnNGbBGT6_rLedhgJGAzpKeEjNibdKklnBc4oZ1w4lLJyJmeiWHheqPqrMpKb9H94pCqjsrssJhG5idHcOL13vN8nShw/s640/signup5.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "trebuchet ms" , sans-serif;">5. This takes you to a page where you specify an API Key name and click <b>Generate</b>:</span></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcicKx7tKMytDrJNX77NeF9EIamJHVQpltHvwa5GXeMXZVUiU8As74-UG0WUsKNbyivbgo-JWwN8q-6DdqPiwB1imE7v9z07b9p1aMURCxRj0dl2bCHavik2-ekkQLSIMb2DBfNg/s1600/signup6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="614" data-original-width="880" height="444" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcicKx7tKMytDrJNX77NeF9EIamJHVQpltHvwa5GXeMXZVUiU8As74-UG0WUsKNbyivbgo-JWwN8q-6DdqPiwB1imE7v9z07b9p1aMURCxRj0dl2bCHavik2-ekkQLSIMb2DBfNg/s640/signup6.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "trebuchet ms" , sans-serif;">Note that you can use any API Key name from this screen. The API Key name is <i>not</i> used as part of the relay security but is just FYI.</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">6. After you click on Create Key, SendGrid displays the key and provides some details on how to configure your client:</span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhemqF0jtiKKBY611XwjDyPFQ33DbL0L_2oXW_UfM5oc7GGgDhIzwj4UIlbIgB4m7Kzqxt0-SiPaUhItnUbb2VPna_Zn2f62uV4WeyKZ7ReCuRPhvT3A13varxdti80D3agFbMA6Q/s1600/signup7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="623" data-original-width="954" height="416" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhemqF0jtiKKBY611XwjDyPFQ33DbL0L_2oXW_UfM5oc7GGgDhIzwj4UIlbIgB4m7Kzqxt0-SiPaUhItnUbb2VPna_Zn2f62uV4WeyKZ7ReCuRPhvT3A13varxdti80D3agFbMA6Q/s640/signup7.png" width="640" /></a></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">Please note that in this screenshot, I have obscured MY API key. Since that key is both a user name AND a password for your (or in this case my) account, you need to keep it safe. I recommend at this point cut/past the key form the web browser and save it to a text file. You can not retrieve the plaintext key again so be careful.</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">Now that you have your account setup and an API key generated, you now need to configure IIS to use this.</span></div>
<div>
<br /></div>
<div>
<b><span style="font-family: "verdana" , sans-serif;">Install IIS and configure an Email Relay</span></b></div>
</div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">The next step is to install IIS and configure the IIS SMTP relay. I assume you are using WIndow Sever 2019. If you need to, you can always download an eval version to use. That gives you 6 months use before you need to activate (or just install and configure a new server). </span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">7. Install IIS in Windows Server</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">You use the Add-WindowsFeature command to add IIS to your Windows Server host (e.g. on SRV1.Reskit.Org), like this:</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYqopPax86qktlOwIMYfmTOr_nmj13NICQGrYSg1BnDKUW1iH-Wkn7Ft9aaBqR3RrYrLpnaBMEPRaMuQ1TXbXQF5peR0oZwTHqNhhNuS3iADbs6DotqYsyIqWLKJotQwrDMPug7g/s1600/IIS1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="316" data-original-width="975" height="206" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYqopPax86qktlOwIMYfmTOr_nmj13NICQGrYSg1BnDKUW1iH-Wkn7Ft9aaBqR3RrYrLpnaBMEPRaMuQ1TXbXQF5peR0oZwTHqNhhNuS3iADbs6DotqYsyIqWLKJotQwrDMPug7g/s640/IIS1.png" width="640" /></a></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">For some reason, this needs a reboot - so go do it!</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">8. Configure IIS Relay on SRV1</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">The final step is to set up the SMTP Relay on SRV1. You use the IIS 6 MMC console for this. So start by bringing up the SMTP server tool either from the Start menu (Start/Windows Administrative Tools\Internet Information Server (IIS) 6 Manager or run the application:</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">C:\Windows\system32\inetsrv\InetMgr6.exe.And select the IIS SMTP Server:</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWODe83OQYH7_jQn62GEXaPoGPQyoBklEZVRwh7VpJuylttZGMunc4PMJvesBfMupjOjywQ-2u6Ss2lTqrAnbcAIxTBIkByFVBIRDStRT3VveDjBfs-AGImzlTZquaBmLx8yq_Xg/s1600/IIS2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="249" data-original-width="641" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWODe83OQYH7_jQn62GEXaPoGPQyoBklEZVRwh7VpJuylttZGMunc4PMJvesBfMupjOjywQ-2u6Ss2lTqrAnbcAIxTBIkByFVBIRDStRT3VveDjBfs-AGImzlTZquaBmLx8yq_Xg/s640/IIS2.png" width="640" /></a></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: left;">
Now bring up the SMTP Virtual Server properties dialog by right-clicking on the SMTP Virtual Server and selecting Properties then click on Access. And select Relay - here you configure which systems can connect. For testing, I set "All except the list below" and leave the list blank, like this:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfIediRyNd0bAh4DwPtipkbrcImqnC6mqt5mzpPVJYTZ_IyRkqU0nP2FzAciLEdY8KlI8IFmj12ZIhybF0uBlcdiSbytr8Nt6H5kX8fUSoLk6XyewnGIq1JYH_nqxgn-fSwGEBhg/s1600/IIS3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="379" data-original-width="379" height="398" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfIediRyNd0bAh4DwPtipkbrcImqnC6mqt5mzpPVJYTZ_IyRkqU0nP2FzAciLEdY8KlI8IFmj12ZIhybF0uBlcdiSbytr8Nt6H5kX8fUSoLk6XyewnGIq1JYH_nqxgn-fSwGEBhg/s400/IIS3.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "trebuchet ms" , sans-serif;">Click OK.</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "trebuchet ms", sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: "trebuchet ms", sans-serif;">Next click on the Delivery tab in the SMTP Virtual Server Properties:</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWjMEWd0b7lhL7epIdF6rUDtR10Rn2r2_ifc2mt2u5ZHAlEHfV_h7eGI0Ys7E1fcGo9Skq0GNdTrLjj1o1_vTEh-QLA_azMBXC6kGlmHtbe1oZ9GhF2I7q5rkLSVkxWGsUCXe8zg/s1600/IIS4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="454" data-original-width="388" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWjMEWd0b7lhL7epIdF6rUDtR10Rn2r2_ifc2mt2u5ZHAlEHfV_h7eGI0Ys7E1fcGo9Skq0GNdTrLjj1o1_vTEh-QLA_azMBXC6kGlmHtbe1oZ9GhF2I7q5rkLSVkxWGsUCXe8zg/s400/IIS4.png" width="341" /></a></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">From here, click on outbound security and set the user name and password. From this dialog box, select Basic Authentication then enters the user name and password. In this case, the user id is 'apikey' and the password is your API key you set up earlier. Configuring it looks like this:</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIyfIt_0Gai6PVwZCA1DsyzWoaa8FYj_X9Q12w28T8iDHKUs_9X4jX2itqmv5fros7-XIj2UWL_7StE7QG77i95Fd4vAdAjquBSzH_QmEOMWmAEPziDGdDAa6XDBgJob46DR6hwA/s1600/IIS5png.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="455" data-original-width="400" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIyfIt_0Gai6PVwZCA1DsyzWoaa8FYj_X9Q12w28T8iDHKUs_9X4jX2itqmv5fros7-XIj2UWL_7StE7QG77i95Fd4vAdAjquBSzH_QmEOMWmAEPziDGdDAa6XDBgJob46DR6hwA/s400/IIS5png.png" width="351" /></a></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">After clicking OK, click on the Advanced Delivery button to bring up the Advanced Delivery dialog from which you enter the SendGrid server details like this:</span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3fx73FY2JansBOMVk-4uyF83uuNdh87gZNco4ApXCAP4IgfwFmDcbh0n9L5gWSZ7RUHeA3ZGht14rxmI01nIKJdNgaJud4HxIix2vR21quswub8a2LGo54W2m1Llr9HU0hMZDYQ/s1600/IIS5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="457" data-original-width="399" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3fx73FY2JansBOMVk-4uyF83uuNdh87gZNco4ApXCAP4IgfwFmDcbh0n9L5gWSZ7RUHeA3ZGht14rxmI01nIKJdNgaJud4HxIix2vR21quswub8a2LGo54W2m1Llr9HU0hMZDYQ/s400/IIS5.png" width="348" /></a></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">And after clicking OK, your relay should be all set up and ready to go. You must need to test it.</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "verdana" , sans-serif;"><b>Testing your relay</b></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">Once you have the relay working on SRV1, you can test it using this little script:</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<div>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Test-SendGrid.ps1 - script to test send grid</b></span></div>
<div>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span></div>
<div>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Setup key variables</b></span></div>
<div>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$To = 'tfl@psp.co.uk'</b></span></div>
<div>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Fr = 'SRV1@reskit.org'</b></span></div>
<div>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Subj = 'Test Email via SendGrid'</b></span></div>
<div>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$body = "testing`ntesting`nTESTING"</b></span></div>
<div>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$SmtpSrv = 'SRV1.Reskit.Org'</b></span></div>
<div>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span></div>
<div>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># And send the email</b></span></div>
<div>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>Send-Mailmessage -To $To -From $Fr -Subj $Subj -Body $body -SmtpServer $SmtpSrv</b></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: "trebuchet ms" , sans-serif;">After sending the mail, you can check in your email client to ensure the mail is sent. If you don't get it, as ever, check your junk mail folder. If that doesn't work do it over and do so very carefully! My personal experience is that API keys can be a challenge. You may need to generate another key.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">After sending the mail, you should check in your email client to ensure the mail has been sent and you have received it (it may be in your Junk folder). If you do not get the mail, you need to do some SMTP relay troubleshooting. </span></div>
</div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "verdana" , sans-serif;"><b>Summary</b></span></div>
<div>
<span style="font-family: "verdana" , sans-serif;"><b><br /></b></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">SendGrid provides a simple SMTP EMail Relay Service which you can use to test SMTP enabled applications or services like FSRM.</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">Thanks to those nice people at Sendgrid for a most useful service!</span></div>
<div>
<br /></div>
</div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-5384857.post-24375708839358782942020-03-12T00:00:00.000+00:002020-04-01T19:52:08.897+01:00PowerShell 7, VS Code, and the PowerShell 7 ISE Extension<div dir="ltr" style="text-align: left;" trbidi="on">
<span style="font-family: "trebuchet ms" , sans-serif;"><b>Introduction and Background</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">Welcome to this post, a part of this </span><span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>#PS7NOW</b></span><span style="font-family: "trebuchet ms" , sans-serif;"> blog series - I hope you are enjoying them. Before getting to my topic, I assume that you know what PowerShell 7 is and are familiar with Windows PowerShell. </span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">The Windows PowerShell ISE, a tool I used extensively ever since early beta versions in Windows PowerShell V2, does NOT feature in PowerShell 7. </span><span style="font-family: "trebuchet ms" , sans-serif;"> You might say, it's pining for the fjords (although it's still shipped in Windows and is likely to be supported for years and years). </span><span style="font-family: "trebuchet ms" , sans-serif;">But however you describe it - it's feature complete and is not going to support PowerSell 7. Replacing the ISE is a new product: Visual Studio Code, or VS Code.</span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">VS Code is light-weight, cross-platform (ie Linux, Mac, Windows), and open-source code editing tool. W</span><span style="font-family: "trebuchet ms" , sans-serif;">hich sounds like no big deal, but if you are an ISE user and are utilising Windows PowerShell, VS Code is in your future. </span><span style="font-family: "trebuchet ms" , sans-serif;">For more details on VS Code, see <a href="https://code.visualstudio.com/docs">https://code.visualstudio.com/docs</a>.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><b>VS Code</b></span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">I must confess, the early versions of VS Code I used were under-whelming, and I much preferred the ISE. </span><span style="font-family: "trebuchet ms" , sans-serif;">And given that PowerShell Core was also in the early days, sticking with the ISE and Windows PowerShell for day to day activities made sense.</span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">But for me, the release of PowerShell 7 and the incredible velocity behind the both PowerShell 7 and VS Code product have changed my view. </span><span style="font-family: "trebuchet ms" , sans-serif;">I now use VS Code for my day to day work. </span><span style="font-family: "trebuchet ms" , sans-serif;">I still use the ISE, but only to install PowerShell 7 and VS Code.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">Some features I like in VS Code include:-</span><br />
<ul style="text-align: left;">
<li><span style="font-family: "trebuchet ms" , sans-serif;">Workspaces - this is a set of related folders/files which makes it easy to keep things together even when they are spread out in filestore.</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">Side by Side edit windows - makes comparing files, and leveraging code from one into another so much simpler. </span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">Built-in spell check - yes it's an extension, but typos in comments are less likely. </span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">The extensibility and customizability - you really can have it your way.</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">PS Script analyzer is built in - so I get hints about poor code as I type.</span></li>
</ul>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">And, and, and...</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<span style="font-family: "trebuchet ms" , sans-serif;">For more details on VS Code, see: <a href="https://code.visualstudio.com/docs">https://code.visualstudio.com/docs</a>.</span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;"><b>VS Code Extensions</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">VS Code was built to be extended. </span><span style="font-family: "trebuchet ms" , sans-serif;">An extension adds functionality, such as spell-checking or markdown checking. </span><span style="font-family: "trebuchet ms" , sans-serif;">I originally authored this blog post using Markdown, with the Markdown All In One Extension. </span><span style="font-family: "trebuchet ms" , sans-serif;">If I am to author in Markdown, VS Code is my go-to tool. </span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">I am working on a book and use Github Gists. To assist in managing my Gists, I also use the GistPad Extension. </span><span style="font-family: "trebuchet ms" , sans-serif;">It makes handling Gists so much easier. The integration between VS Code and GitHub, via the extension, is really useful.</span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">To customise the colour scheme of VS Code - you can find many extensions providing additional themes. </span><span style="font-family: "trebuchet ms" , sans-serif;">And as a hint, some of these themes are better than others! </span><span style="font-family: "trebuchet ms" , sans-serif;">For details on the available extensions (and there are a lot) see <a href="https://marketplace.visualstudio.com/VSCode">https://marketplace.visualstudio.com/VSCode</a>.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span><span style="font-family: "trebuchet ms" , sans-serif;">And of course, a great extension anyone using ISE is going to want to get is the PowerShell ISE extension that makes VS code feel more like the ISE, at least colour wise.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><b>Installing VS Code</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">To install VS Code, well - there's a PowerShell script for that too. </span><span style="font-family: "trebuchet ms" , sans-serif;">Naturally! </span><span style="font-family: "trebuchet ms" , sans-serif;">It is called </span><span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>Install-VSCode</b></span><span style="font-family: "trebuchet ms" , sans-serif;"> and you download it from the PS Gallery. </span><span style="font-family: "trebuchet ms" , sans-serif;">That script when you run it, downloads and installs the latest version of VS Code and provides you with flexibility over exactly what to install.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">You can find any number of cute 1-liners, but here's a more workman-like, step by step, and hopefully clearer installation snippet: </span><br />
<br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Get and save Install-VSCode installation script</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Assumes C:\Foo exists</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>Set-Location -Path C:\Foo</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>Save-Script -Name Install-VSCode -Path C:\Foo</b></span><br />
<br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Create a list of extensions to add when installing</b></span><br />
<b style="color: #660000; font-family: "courier new", courier, monospace;">$Extensions = 'Streetsidesoftware.code-spell-checker',</b><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> 'yzhang.markdown-all-in-one',</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> 'davidanson.vscode-markdownlint',</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> 'vsls-contrib.gistfs'</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Now install VS Code</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$InstallHT = @{</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> BuildEdition = 'Stable-System'</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> AdditionalExtensions = $Extensions</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> LaunchWhenDone = $true</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>}</b><b>.\Install-VSCode.ps1 @InstallHT</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">The install script is able to load different versions (<b>Stable-System</b>, <b>Stable-User</b>, <b>Insider-System</b>, <b>Insider-User</b>). </span><span style="font-family: "trebuchet ms" , sans-serif;">Different builds provide more recent features but maybe less well tested and less reliable. </span><span style="font-family: "trebuchet ms" , sans-serif;">I use <b>Stable-System</b> and have not had any issues whatsoever (aside from being able to get PSReadline to behave - but that is a rant for another day)</span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">When you run this snippet, for example in the Windows PowerShell or the ISE, you may see some warning messages when VS Code adds the extensions. Y</span><span style="font-family: "trebuchet ms" , sans-serif;">ou can ignore these errors. FWIW </span><span style="font-family: "trebuchet ms" , sans-serif;">It seems these warning messages have gone away with the latest builds of VS Code so you may not see these today.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">This snippet takes around 30-40 seconds and rewards you, in the end, with VS Code open and ready for use.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">You may have noticed reading that snippet that it did not explicitly mention the PowerShell extensions. </span><span style="font-family: "trebuchet ms" , sans-serif;">The good news is that the script installs this extension by default.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;">It sure seems like a good idea to me! </span><span style="font-family: "trebuchet ms" , sans-serif;">However, the ISE theme is not used by default - but there are scripts to fix that too.</span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">Here are a two screenshots of VS code (with the ISE Theme) and the Windows PowerShell ISE.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_Dbj4A9-zzWJ6_TjIm8eAm4yi2h0rlXN-BLcVUExv1duPaxsViACaXozHTA1ykMSDY3kfTFCUf2zuLEStw_tBoen5iGCUGDjnhwS5XiDOwgCjOpDr7mTWFisWD6wHYu3RV0Rufg/s1600/2020-03-20_11-58-06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="953" data-original-width="1600" height="380" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_Dbj4A9-zzWJ6_TjIm8eAm4yi2h0rlXN-BLcVUExv1duPaxsViACaXozHTA1ykMSDY3kfTFCUf2zuLEStw_tBoen5iGCUGDjnhwS5XiDOwgCjOpDr7mTWFisWD6wHYu3RV0Rufg/s640/2020-03-20_11-58-06.png" width="640" /></a></div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_Dbj4A9-zzWJ6_TjIm8eAm4yi2h0rlXN-BLcVUExv1duPaxsViACaXozHTA1ykMSDY3kfTFCUf2zuLEStw_tBoen5iGCUGDjnhwS5XiDOwgCjOpDr7mTWFisWD6wHYu3RV0Rufg/s1600/2020-03-20_11-58-06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="953" data-original-width="1600" height="380" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_Dbj4A9-zzWJ6_TjIm8eAm4yi2h0rlXN-BLcVUExv1duPaxsViACaXozHTA1ykMSDY3kfTFCUf2zuLEStw_tBoen5iGCUGDjnhwS5XiDOwgCjOpDr7mTWFisWD6wHYu3RV0Rufg/s640/2020-03-20_11-58-06.png" width="640" /></a></div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">For more details on setting up VS Code, see: </span><a href="https://code.visualstudio.com/docs/setup/setup-overview" style="font-family: "trebuchet ms", sans-serif;">https://code.visualstudio.com/docs/setup/setup-overview</a><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><b>Managing VS Code Extensions</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">You can manage and configure VS Code extensions inside VS Code or externally. </span><span style="font-family: "trebuchet ms" , sans-serif;">In early versions of VS Code, you had to hand configure a JSON file to change settings, but today, there's a gui for that. And o</span><span style="font-family: "trebuchet ms" , sans-serif;">nce you install VS Code, you can manage extensions (from PowerShell) like this:</span><br />
<br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Sets the root path for extensions</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>code --extensions-dir </b></span><br />
<br />
<br />
<dir></dir><b style="color: #660000; font-family: "courier new", courier, monospace;"># Lists the installed extensions.</b><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>code --list-extensions</b></span><br />
<br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Uninstalls an extension.</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>code --uninstall-extension (<extension-id> | <extension-vsix-path>)</extension-vsix-path></extension-id></b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;"><b>VS Code PowerShell Extension</b></span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><b><br /></b></span>
<span style="font-family: "trebuchet ms" , sans-serif;">As I mentioned earlier, one extension most ISE users are going to want to get is the Powershell ISE extension. </span><span style="font-family: "trebuchet ms" , sans-serif;">The PowerShell extension adds great language support and great features including: </span><br />
<ul style="text-align: left;">
<li><span style="font-family: "trebuchet ms" , sans-serif;">PowerShell Syntax highlighting</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">Tab completion</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">Code snippets</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">IntelliSense for cmdlets, parameters, and more</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">The rule-based analysis provided by PowerShell Script Analyzer</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">Definition tracking and a "Go to definition" for cmdlets and variables</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">Find references of commands and variables</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">Document and Workspace symbol discovery</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">Run the selected section of PowerShell code using F8</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">Launch online help for the symbol under the cursor using Ctrl + F1</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">Local script debugging and basic interactive console support</span></li>
<li><span style="font-family: "trebuchet ms" , sans-serif;">A colour scheme that looks familiar.</span></li>
</ul>
<span style="font-family: "trebuchet ms" , sans-serif;">In my experience, VS Code is just different enough from the ISE to make those first few hours a tad painful. </span><span style="font-family: "trebuchet ms" , sans-serif;">But quickly, very quickly, VS Code begins to make the ISE look quite dated. </span><span style="font-family: "trebuchet ms" , sans-serif;">I love having PS Script Analyzer run as I am entering code - it helps me to write better code And the side by side editing has made my book-writing task a lot simpler. </span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">For more details on the extension, see <a href="https://code.visualstudio.com/docs/languages/powershell">https://code.visualstudio.com/docs/languages/powershell</a>.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><b>Configuring the PowerShell Extension</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">You can update and configure extensions from within VS Code itself. </span><span style="font-family: "trebuchet ms" , sans-serif;">In early versions of VS Code, any configuration had to be done by hand-editing a JSON file. </span><span style="font-family: "trebuchet ms" , sans-serif;">Later versions added a configuration GUI meaning you can do most configuration simply using the GUI.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;">But you can also directly edit the **settings.json** file to update the configuration.</span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">The VS Code user settings file is contained in the file:</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;">**C:\Users\<user>\AppData\Roaming\Code\User\settings.json**</user></span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">My current settings.json file looks like this:</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>{</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "workbench.colorTheme": "PowerShell ISE",</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "window.zoomLevel": 1,</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "editor.fontFamily": "'Cascadia Code',Consolas,'Courier New'",</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "editor.tabCompletion": "on",</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "workbench.editor.highlightModifiedTabs": true,</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "powershell.codeFormatting.useCorrectCasing": true,</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "files.autoSave": "onWindowChange",</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "files.defaultLanguage": "powershell"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>}</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">A neat feature of VS Code - if you update that file and save it, VS Code uses the newly created configuration automatically.</span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">In the earlier snippet, you installed VS Code.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;">At the end of the configuration, you could do this to further configure VS Code:</span><br />
<br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Download Cascadia Code font from GitHub</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$CascadiaFont = 'Cascadia.ttf' # font name</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$CascadiaRelURL = 'https://github.com/microsoft/cascadia-code/releases'</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$CascadiaRelease = Invoke-WebRequest -Uri $CascadiaRelURL # Get all of them</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$CascadiaPath = "https://github.com" + ($CascadiaRelease.Links.href | </b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> Where-Object { $_ -match "($cascadiaFont)" } | </b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> Select-Object -First 1)</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$CascadiaFile = "C:\Foo\$CascadiaFont"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Download Cascadia Code font file</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>Invoke-WebRequest -Uri $CascadiaPath -OutFile $CascadiaFile</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Install Cascadia Code</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$FontShellApp = New-Object -Com Shell.Application</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$FontShellNamespace = $FontShellApp.Namespace(0x14)</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$FontShellNamespace.CopyHere($CascadiaFile, 0x10)</b></span><br />
<br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Install the font using Shell.Application COM object</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Destination = (New-Object -ComObject Shell.Application).Namespace(0x14)</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Destination.CopyHere(</b><b>$CascadiaFile</b><b>,0x10)</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span><span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Create a short cut to VSCode</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$SourceFileLocation = "$env:ProgramFiles\Microsoft VS Code\Code.exe"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$ShortcutLocation = "C:\foo\vscode.lnk"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Create a new wscript.shell object</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$WScriptShell = New-Object -ComObject WScript.Shell</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Shortcut = $WScriptShell.CreateShortcut($ShortcutLocation)</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Shortcut.TargetPath = $SourceFileLocation</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>#Save the Shortcut to the TargetPath</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Shortcut.Save()</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Create a short cut to PowerShell 7</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$SourceFileLocation = "$env:ProgramFiles\PowerShell\7-Preview\pwsh.exe"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$ShortcutLocation = 'C:\Foo\pwsh.lnk'</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Create a new wscript.shell object</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$WScriptShell = New-Object -ComObject WScript.Shell</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Shortcut = $WScriptShell.CreateShortcut($ShortcutLocation)</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Shortcut.TargetPath = $SourceFileLocation</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Save the Shortcut to the TargetPath</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Shortcut.Save()</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$XML = @'</b></span><br />
<b style="color: #660000; font-family: "courier new", courier, monospace;">xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"</b><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> Version="1"></b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> </b></span><b style="color: #660000; font-family: "courier new", courier, monospace;">'@</b><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$XML | Out-File -FilePath C:\Foo\Layout.xml</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span><span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Import a startlayut.XML file</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>Import-StartLayout -LayoutPath C:\Foo\Layout.xml -MountPath C:\</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b><br /></b></span><span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Update Local User Settings for VS Code</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># This step in particular needs to be run in PowerShell 7!</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$JSON = @'</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>{</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "editor.fontFamily": "'Cascadia Code',Consolas,'Courier New'",</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "editor.tabCompletion": "on",</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "files.autoSave": "onWindowChange",</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "files.defaultLanguage": "powershell",</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "powershell.codeFormatting.useCorrectCasing": true,</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "window.zoomLevel": 1,</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "workbench.editor.highlightModifiedTabs": true,</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "workbench.colorTheme": "PowerShell ISE",</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> }</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>'@</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$JHT = ConvertFrom-Json -InputObject $JSON -AsHashtable</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$PWSH = "C:\\Program Files\\PowerShell\\7\\pwsh.exe"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$JHT += @{</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> "terminal.integrated.shell.windows" = "$PWSH"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>}</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Path = $Env:APPDATA</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$CP = '\Code\User\Settings.json'</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$Settings = Join-Path $Path -ChildPath $CP</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$JHT |</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> ConvertTo-Json |</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> Out-File -FilePath $Settings</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">This snippet downloads and installs a new font, Cascadia Code and creates two new shortcuts for your toolbar. </span><span style="font-family: "trebuchet ms" , sans-serif;">The snippet also updates the settings.json file with certain useful settings.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><b>Summary</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">PowerShell 7, has shipped. </span><span style="font-family: "trebuchet ms" , sans-serif;">If you are a Windows PowerShell, and particularly a fan of the ISE, VS Code is a tool to take on board. </span><span style="font-family: "trebuchet ms" , sans-serif;">To assist you, the PowerShell extension makes VS Code easier to adopt. </span><span style="font-family: "trebuchet ms" , sans-serif;">And the extensions available take VS Code to the next level.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><b>TL;DR: PowerShell 7 with VS Code with PowerShell 7 rocks.</b></span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><b>The PowerShell Extension to VS Code just rocks more!</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">What are you waiting for?</span><br />
<div>
<br /></div>
</div>
Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-5384857.post-37887187294881282272020-03-10T17:10:00.001+00:002020-03-11T10:59:36.523+00:00PowerShell 7 Chain and Ternary Operators<div dir="ltr" style="text-align: left;" trbidi="on">
<span style="font-family: "trebuchet ms" , sans-serif;"><b>Introduction and Background</b></span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">Welcome to this post as part of this PowerShell 7's </span><b><span style="font-family: "verdana" , sans-serif;">#PSBlogWeek</span></b><span style="font-family: "trebuchet ms" , sans-serif;">! I hope you are enjoying the many posts.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">As I started to think about this topic, an old Grateful Dead song kept running through my mind </span><span style="font-family: "trebuchet ms" , sans-serif;">"<i>Operator, Can you help m? Help me if you please...</i>" </span><span style="font-family: "trebuchet ms" , sans-serif;">For a live version, listen to <a href="https://www.youtube.com/watch?v=TytIqm_d7uE">https://www.youtube.com/watch?v=TytIqm_d7uE</a>.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">So here is some information about a couple of the great new features in PowerShell 7, in particular, the Pipeline Chain Operators and the Ternary Operators.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">In the days of Windows PowerShell, extending the PowerShell language was done by the Microsoft Windows PowerShell team. </span><span style="font-family: "trebuchet ms" , sans-serif;">With the move to open source, more developers can, and have, made it possible to do a lot more in PowerShell 7. </span><span style="font-family: "trebuchet ms" , sans-serif;">PowerShell's language was modelled on C# - Jeff Snover has often said that PowerShell is on the glide scope to C#.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">With PowerShell 7 comes two new operator sets: The Pipeline Chain Operators and the Ternary operators. </span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">The Pipeline Chain operators (</span><span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>||</b></span><span style="font-family: "trebuchet ms" , sans-serif;"> and </span><span style="color: #990000; font-family: "courier new" , "courier" , monospace;"><b>&&</b></span><span style="font-family: "trebuchet ms" , sans-serif;">) enable you to allow conditional execution of commands depending on whether the previous command succeeded for failed. You use the Ternary operators (</span><b><span style="color: #660000; font-family: "courier new" , "courier" , monospace;">? </span></b><span style="font-family: "trebuchet ms" , sans-serif;">and </span><span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>:</b></span><span style="font-family: "trebuchet ms" , sans-serif;">) as a short-hand way of implementing if/else type statements. </span><span style="font-family: "trebuchet ms" , sans-serif;">These are popular among C# developers and Bash users and have long been requested within PowerShell.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">These operators add new functionality to PowerShell 7. </span><span style="font-family: "trebuchet ms" , sans-serif;">They are nice when used carefully, but can reduce the clarity of production code. Let's look at them in more detail. </span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><b>PIpeline Chain Operators</b></span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">The pipeline Chain operators enable conditional execution of commands depending on whether a previous command succeeded or failed. There are two pipeline chain operators: </span><span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>&&</b></span><span style="font-family: "trebuchet ms" , sans-serif;"> and </span><span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>||</b></span><span style="font-family: "trebuchet ms" , sans-serif;">. </span><span style="font-family: "trebuchet ms" , sans-serif;">These operators were added to PowerShell 7 Preview 5. </span><span style="font-family: "trebuchet ms" , sans-serif;">Prior to PowerShell 7, you could have used If/Else to do the same thing,</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">These operators come originally from Posix. </span><span style="font-family: "trebuchet ms" , sans-serif;">POSIX shells call this as AND-OR lists. </span><span style="font-family: "trebuchet ms", sans-serif;">The idea is that depending on whether a command is successful, you can do different things.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><b>What is it used for?</b></span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">If a pipeline is successful, this operator allows you to run some other pipeline. </span><span style="font-family: "trebuchet ms" , sans-serif;">But if the first pipeline is unsuccessful, you can run a different pipeline. </span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">For example:</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Create an SSH key pair - if successful copy </b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># the public key to clipboard</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>ssh-keygen -t rsa -b 2048 && Get-Content -Raw ~\.ssh\id_rsa.pub || clip</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">If the keys are generated successfully using SSH-KEYGEN (and content returned from </span><span style="color: #660000; font-family: Courier New, Courier, monospace;"><b>Get-Content</b></span><span style="font-family: "trebuchet ms" , sans-serif;">), then the command copies it to the clipboard. </span><span style="font-family: "trebuchet ms" , sans-serif;">Without these operators you would have used if/else and/or try/catch - the chain operators make things a bit shorter.</span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;"><b>Ternary Operators</b></span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">The ternary operator evaluates a Boolean expression and returns the result of one of the two expressions, depending on whether the Boolean expression evaluates to true or false.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;">This sounds more complex than it is (see the example below!) </span><span style="font-family: "trebuchet ms" , sans-serif;">These operators were added to PowerShell 7 Preview 4. </span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><b>What Is It Used For?</b></span><br />
<span style="font-family: "trebuchet ms" , sans-serif;">You typically use this operator mainly to create a string depending on the value of a boolean variable or expression. </span><span style="font-family: "trebuchet ms" , sans-serif;">For example, y</span><span style="font-family: "trebuchet ms" , sans-serif;">ou could create a string that displayed whether an AD user account was enabled based on the user's <b>Enabled</b> property or display whether a user is using PowerShell on a Mac. Like this:</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Is User Enabled?</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Create 2 strings</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$UEMsg1 = "This user IS enabled in AD"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$UEMsg2 = "This user IS NOT enabled in AD"</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Get Details</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$UserEnabled = (Get-ADUser -Identity $UserName).Enabled</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Set Enabled/Disable String</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$UserEnabledStr = $UserEnabled ? $UEMsg1 : $UEMsg2</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># What does this show for an enabled user:</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$UserEnabledStr</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>This user IS enabled in AD</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>#</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Anotehr example</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>$IsMacOS ? 'Yes' : 'No'</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;"><b>You Can but Should You?</b></span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">I like these new operators but am not likely to use them in code I write. </span><span style="font-family: "trebuchet ms" , sans-serif;">Except maybe to demonstrate them. </span><span style="font-family: "trebuchet ms" , sans-serif;">I really do not, yet, see a great use case, except at the console. </span><span style="font-family: "trebuchet ms" , sans-serif;">As an example of this, look at the chain operator example above. That snippet executes a command, and if successful copies a file to the clipboard. </span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">Personally, I'd have written it more like this:</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># Create an SSH key pair - if successful, copy</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># the public key to clipboard</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>try {</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> ssh-keygen -t rsa -b 2048</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>}</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>Catch {</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b> # handle terminating error - left as an exercise for the reader</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>}</b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b># then </b></span><br />
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>Get-Content -Raw ~\.ssh\id_rsa.pub | clip</b></span><br />
<br />
<span style="font-family: "trebuchet ms" , sans-serif;">If I was running this from the console, I'd just run ssh-keygen. If it ran ok, then I'd type Get-Content and pipe the output to the clipboard. </span><span style="font-family: "trebuchet ms" , sans-serif;">Typing longer lines of code is almost certain to introduce typos, especially given my lousy typing. </span><span style="font-family: "trebuchet ms" , sans-serif;">I find doing things step by step is easiest - both to write and to understand months later when the code needs modification.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">These operators have the potential to reduce the clarity of production code. </span><span style="font-family: "trebuchet ms" , sans-serif;">Unless you know these operators, their meaning is not easy to discern. </span><span style="font-family: "trebuchet ms" , sans-serif;">Operators like -Contains, -Eq, and -Match are both named so as to give at least some clue to their use. </span><span style="font-family: "trebuchet ms" , sans-serif;">The '?' character an alias for Where-Object and the ':' used in PSDrive letters leading to overloaded operators. </span><span style="font-family: "trebuchet ms" , sans-serif;">And that can diminish the readability of production code. </span><span style="font-family: "trebuchet ms" , sans-serif;">I am sure mileage varies - and would love to hear comments as well as seeing more great use cases.</span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;"><b>Summary</b></span><br />
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span>
<span style="font-family: "trebuchet ms" , sans-serif;">TL;DR: Great new operators that bring requested C# Features to PowerShell - Just use them wisely.</span><br />
<div>
<br /></div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5384857.post-51489263407133683422020-03-09T17:14:00.001+00:002020-03-10T13:08:02.587+00:00Deploying and Managing Active Directory with PowerShell 7<div dir="ltr" style="text-align: left;" trbidi="on">
I am in the process of writing <a href="https://smile.amazon.com/PowerShell-7-Pros-Thomas-Lee/dp/1119644720/ref=smi_www_rco2_go_smi_g8217842112?_encoding=UTF8&%2AVersion%2A=1&%2Aentries%2A=0&ie=UTF8" target="_blank">a book on PowerShell 7</a> and one chapter is devoted to deploying and managing Active Directory. When I began looking at doing the book, it was early days for PowerShell core, and coverage was kind of poor. Early on, the AD modules did not seem to be particularly usable from within what was PowerShell Core 6.x. But having completed the chapter using PowerShell 7 RC3 and RTM, I am pleased to find that AD deployment and management works well with PowerShell 7 (and VS Code).<br />
<br />
<b>Background</b><br />
<b><br /></b>
PowerShell 7 is based on .NET Core 3.1, whereas Windows PowerShell is based in the full .NET Framework. This means that some modules, particularly those below the System32 folder, do not work in PowerShell 7 natively.<br />
<br />
The PowerShell team's compatibility solution for older modules is to leverage remoting. When you attempt to load a non-compatible module, Import-Module creates a remoting session into a Windows PowerShell endpoint. Then, using implicit remoting, it imports functions into the calling session. Thus you can use the commands in those modules as if they were directly supported.<br />
<br />
The remoting session created uses the same Process transport that it uses to create background jobs. So it's relatively efficient and doesn't require WinRM. If you load multiple modules via compatibility, PowerShell just creates one session. And if you want to enter the session and look around that too is easy to do.<br />
<br />
<b>What DOESN'T Work?</b><br />
<b><br /></b>
This compatibility solution works very well but is not a universal get out of jail card. A very small number of modules will never work either directly or via the compatibility solution. Because the solution depends on remoting, some modules do not work due to object serialization that occurs when implicit remoting is invoked. The only solution is for the relevant product team to redevelop their modules (and for at least one module, Update Services, this would require a complete re-engineering of the module). At the time of writing, there are but three modules that simply do not and will not work in PowerShell 7.<br />
<br />
The Update Services module, which you would use to manage WSUS, does not work. With this module, you use object methods to perform administrative functions (unlike almost all other modules that deliver commands or cmdlets rather than offering object Methods). The scripting model used by Update Services is reminiscent of COM programming where you instantiate an object and use its methods. A redesign to use command/cmdlets would be a great solution.<br />
<br />
When you use the compatibility solution with this module, the methods are stripped off so you can't really do anything with the objects. The Update Service module also uses SOAP to communicate with the WSUS Server, and this is not supported in .NET Core. For that reason, without a complete redesign of the module (either to not use methods or to port the module to .NET Core and eliminate SOAP), you must manage WSUS using Windows PowerShell.<br />
<br />
In the early Preview versions of the compatibility feature, had you tried to use some modules, you received hard to understand error messages (and of course, those object methods you need were missing.) Additionally, the error messages that were generated were not actionable and of no value.<br />
<br />
The user experience was rather poor, even if you understood the issue. To avoid a bad user experience to this otherwise useful solution, some modules are blocked from being imported. If you try to import the UpdateServices, Import-Module raises and error. This is a much better user experience given that a few modules simply do not work in PowerShell.<br />
<br />
The Import-Module stops you from loading modules as defined in the <span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><b>powershell.config.json</b></span> file in PowerShell's home folder. This file also holds a list of Experimental Features which you have enabled. In my daily build folder, the file looks like this:<br />
<div style="background-color: #fffffe; line-height: 19px;">
<blockquote class="tr_bq">
<span style="color: #660000; font-family: "courier new" , "courier" , monospace;"><span style="font-size: 14px; white-space: pre;"><b>{
"ExperimentalFeatures": [
"PSCommandNotFoundSuggestion",
"PSCultureInvariantReplaceOperator",
"PSImplicitRemotingBatching",
"PSNullConditionalOperators",
"Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace",
"PSDesiredStateConfiguration.InvokeDscResource"
],
"WindowsPowerShellCompatibilityModuleDenyList": [
"PSScheduledJob",
"BestPractices",
"UpdateServices"
],
"Microsoft.PowerShell:ExecutionPolicy": "RemoteSigned"
}</b></span></span></blockquote>
</div>
As you can see there are only three modules that are simply not going to work in PowerShell 7. For me, this is pretty good going and, at least for WIndows, gives IT Pros little reason not to move forward.<br />
<br />
For those modules that DO work in the compatibility solution, there is one other minor issue you might trip over. The display XML that is used to display objects returned from a command. This display XML is not present in your PowerShell session by default which means default output may not be as nice as you might like for example when viewing the windows feature objects returned by Get-WIndowsFeature. Fortunately, there is a very simple workaround for that - just manually load the display XML.<br />
<br />
<b>So What About AD?</b><br />
<br />
In terms of Active Directory, there are three modules that you need to use:<br />
<ul style="text-align: left;">
<li><b>Server Manager module</b> - this module enables you to add the AD DS feature to a server (which adds the other AD modules).</li>
<li><b>AD Deployment module</b> - this module enables you to create new DCs (effectively do the job of DCPromo).</li>
<li><b>Active Directory module</b> - this module allows you to create, update, and delete objects in the AD Database such as adding users, updating groups, etc</li>
</ul>
The Server Manager module is supported by the compatibility solution and all the key commands work as they should. When you load this module, Import-Module does generate a warning message to warn you that this module is being imported via the compatibility solution. Once the module is imported, you can add, get, and remove windows features.<br />
<br />
One small issue with this module is that the display XML that enables the output from Get-WindowsFeature to look so nice is not present by default in your PowerShell session. If this matters to you, you can deal with this by explicitly importing the display XML like this<br />
<blockquote class="tr_bq">
<b style="color: #660000; font-family: "Courier New", Courier, monospace;">Update-FormatData -PrependPath C:\Windows\System32\WindowsPowerShell\v1.0\modules\servermanager\feature.format.ps1xml</b></blockquote>
The AD Deployment module is also supported via the compatibility solution and was fully functional. I tested the following scenarios<br />
<ul style="text-align: left;">
<li>Create a Forest Root DC</li>
<li>Create a replica DC in the first domain</li>
<li>Create DC(s) in a child Domain</li>
<li>Create an additional Forest and implement a cross-forest trust.</li>
<li>Create, update and remove OU, User, Computer, and group objects and manage group membership as well as other admin tasks (eg change password). </li>
</ul>
<div>
The only relatively minor problem with all of this was that there are no commands to set up the cross-forest trust. To set up the trust, you just use the .NET objects and these work in .NET Core. But of course, that wasn't possible using the module in Windows PowerShell either!<br />
<br /></div>
<div>
The Active Directory module was one of the first modules to be ported and seems to work. I have not tested every scenario, but adding/modifying/removing users/groups/computers, managing OU contents and the like all work just as you would expect.<br />
<br />
You can see the PowerShell 7 scripts that I developed in Github: <a href="https://github.com/doctordns/Wiley20/tree/master/08%20-%20Hyper-V">https://github.com/doctordns/Wiley20/tree/master/08%20-%20Hyper-V</a>. Note that these scripts are currently being developed so may change before the book is published/<br />
<br />
<b>Summary</b></div>
<br />
PowerShell 7 both now with RC2 and when it is fully released supports deploying and managing AD forests and domains. There is a minor issue with display XML and Get-WinowsFeature which has an easy workaround. The key point is that I was able to deploy multiple forests and manage the objects inside the AD as well as with Windows PowerShell.<br />
<br />
If you are a Windows IT Pro and use Windows PowerShell to manage Windows services and applications, you really should try PowerShell 7. It's easy to download and use and you can run it side by side with Windows PowerShell. That can enable you to enjoy the new features where you can but fall back to Windows PowerShell when you need to<br />
<br />
What are you waiting for?<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br /></div>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-5384857.post-21175638424110383022020-03-08T17:22:00.001+00:002020-03-08T17:22:52.552+00:00Remoting With PowerShell 7<div dir="ltr" style="text-align: left;" trbidi="on">
<span style="font-family: Trebuchet MS, sans-serif;">With version 2 of Windows PowerShell came the PowerShell Remoting feature. Remoting worked but was a bit flakey. In Version 3 it was vastly improved. Remoting came with the PowerShell Remoting Protocol (PSRP). You can read about PSRP at <a href="https://docs.microsoft.com/en-gb/openspecs/windows_protocols/ms-psrp">https://docs.microsoft.com/en-gb/openspecs/windows_protocols/ms-psrp</a>.</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: Trebuchet MS, sans-serif;">In Windows PowerShell, all remoting was done using WS-Man, implemented by the WinRM service. With PowerShell 7, you can perform remoting over SSH. This article covers traditional Remtinog via WinRM and looks at what's new with PowerShell 7.</span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: Trebuchet MS, sans-serif; font-size: large;"><b>PowerShell Remoting</b></span><br />
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span>
<span style="font-family: "Trebuchet MS", sans-serif;">Here's a simplistic picture of the WS-Man based remoting stack in PowerShell:</span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4Hjgi1Fw0OuM76ewlORKUkDCZlfqiW29EjZsiFiGdCAfe8TQIYPc-BD47_gJwD-6O42vkEWtxJ8s2cWg0iL-1weOtK2IyO4NWbvhwAKFuxqCCF2sT4Fuu5uXJY0QmAT4XQa9v8w/s1600/Drawing1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Trebuchet MS, sans-serif;"><img border="0" height="232" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4Hjgi1Fw0OuM76ewlORKUkDCZlfqiW29EjZsiFiGdCAfe8TQIYPc-BD47_gJwD-6O42vkEWtxJ8s2cWg0iL-1weOtK2IyO4NWbvhwAKFuxqCCF2sT4Fuu5uXJY0QmAT4XQa9v8w/s320/Drawing1.png" width="320" /></span></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;">At the bottom is HTTP / HTTPs. Remoting uses HTTP and HTTPS to carry objects between remoting clients and remoting targets. Although remoting uses HTTP, the higher levels in this stack encrypt traffic. You can use HTTPS as a transport which provides mutual authentication via certificates which can be useful in some scenarios (eg a DMZ workgroup). </span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;">Simple Object Access Protocol (SOAP) is used to carry the data - the objects exchanged between a remoting client and target. SOAP used XML XML to hold the objects transferred between the client and target. All transferred data (objects) are first serialised into XML and deserialized at the other end. The side effect of this is that methods are stripped off. </span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;">WS-MAN controls the end to end communications for remoting. When a remoting client establishes a connection to a remote machine, it connects to a specific endpoint. The default remoting endpoint is held in the variable <span style="color: #660000;"><b>$PSSessionConfigurationName</b></span>. WS-MAN (implemented by the WInRM service). </span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;">Microsoft adapted the WS-MAN service to work with Windows via the WSMV (WS-Management Protocol Extensions for Windows Vista). You can read about this layer in the Remoting stack at:<a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wsmv/055dc36b-db2a-41ae-a47b-82cbfa0b4a92">https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wsmv/055dc36b-db2a-41ae-a47b-82cbfa0b4a92</a>.</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;">At the top of the stack is PowerShell Remoting Protocol WIth PSRP, remoting clients establish a session with a remoting target and use that session to send structured pipelines to the target and receive the results of those pipelines. Remoting establishes a session which holds state information with what PowerShell terms a runspace. For more information on PSRP, see: <a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-psrp">https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-psrp</a>.</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;">Remoting is a complex subject and this overview necessarily omits much of the lower-level details. </span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif; font-size: large;"><b>Using Remoting</b></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;">You can use remoting in three main ways:</span></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<ul style="text-align: left;">
<li><span style="font-family: Trebuchet MS, sans-serif;">Use </span><b><span style="color: #660000; font-family: Courier New, Courier, monospace;">Enter-PSSession</span></b><span style="font-family: Trebuchet MS, sans-serif;"> to enter a telnet-like remote session. Commands you type are executed on the remoting target and you see the (serialized) results.</span></li>
<li><span style="font-family: Trebuchet MS, sans-serif;">Use </span><span style="color: #660000; font-family: Courier New, Courier, monospace;"><b>Invoke-Command</b></span><span style="font-family: Trebuchet MS, sans-serif;"> to run a script block or a script file on the remoting target.</span></li>
<li><span style="font-family: Trebuchet MS, sans-serif;">Use </span><span style="color: #660000; font-family: Courier New, Courier, monospace;">New-PSSession</span><span style="font-family: Trebuchet MS, sans-serif;"> to create a new remoting session on the remoting target and then use the other two mechanisms to run commands on the target.</span></li>
</ul>
<div>
<span style="font-family: Trebuchet MS, sans-serif;">If you use </span><span style="color: #660000; font-family: Courier New, Courier, monospace;"><b>Enter-PSSession</b></span><span style="font-family: Trebuchet MS, sans-serif;">, PowerShell, in effect, runs a copy of PowerShell on the target host into which you type commands and see the results. State in the remote runspace is maintained until you exit the remoting session. With using </span><span style="color: #660000; font-family: Courier New, Courier, monospace;"><b>Invoke-Command</b></span><span style="font-family: Trebuchet MS, sans-serif;">, PowerShell tears down the remote runspace when the script block or script file has completed.</span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;">If you create a remote session using </span><span style="color: #660000; font-family: Courier New, Courier, monospace;"><b>New-PSSession</b></span><span style="font-family: Trebuchet MS, sans-serif;">, you can use </span><span style="color: #990000; font-family: Courier New, Courier, monospace;"><b>Invoke-Command</b></span><span style="font-family: Trebuchet MS, sans-serif;"> and </span><span style="color: #660000; font-family: Courier New, Courier, monospace;"><b>Enter-PSSession</b></span><span style="font-family: Trebuchet MS, sans-serif;"> and PowerShell maintains state. You can also specify how long PowerShell should keep the remote runspace active.</span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif; font-size: large;"><b>Remoting in PowerShell 7</b></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;">PowerShell 7 implements the same remoting but there are three gotchas:</span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><b>By default, the installation process does NOT create PowerShell 7 remoting endpoints. </b>So after installing PowerShell 7, running </span><span style="color: #660000; font-family: Courier New, Courier, monospace;"><b>Get-PSSessionConfiguration</b></span><span style="font-family: Trebuchet MS, sans-serif;"> shows NO endpoints: </span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWky0LpW4QOU9LSv6WSkzybUypC5M8cNwPzxkTsLUhljepoQam0HCoOougwCjfFd-m5sClGfeTlLWojdTs4XS1DMOZQkOH9KewUeGXHmG8B0sPTs8pKSL2ZZ1blsBAn6K3J2-f8A/s1600/2020-03-08_16-57-49.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="338" data-original-width="464" height="233" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWky0LpW4QOU9LSv6WSkzybUypC5M8cNwPzxkTsLUhljepoQam0HCoOougwCjfFd-m5sClGfeTlLWojdTs4XS1DMOZQkOH9KewUeGXHmG8B0sPTs8pKSL2ZZ1blsBAn6K3J2-f8A/s320/2020-03-08_16-57-49.png" width="320" /></a></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;">You can enable the PowerShell 7 endpoints by using </span><span style="color: #660000; font-family: Courier New, Courier, monospace;"><b>Enable-PSRemoting</b></span><span style="font-family: Trebuchet MS, sans-serif;">. After enabling remoting, you see two PowerShell 7 endpoints, like this.</span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgMoGuGRuMZy1OrpHa0lZFMrTFVgGRRQnFJ4sZ27klyZGvGwwgSBOyzOVDNHRTs60Jr553TS8k9JAMg1uLs9OL0OwveysIJmfHDycageUqvalhFMAEQ3MQ-rUfCzio0rPPsmCrLQ/s1600/2020-03-08_17-02-28.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="404" data-original-width="1099" height="232" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgMoGuGRuMZy1OrpHa0lZFMrTFVgGRRQnFJ4sZ27klyZGvGwwgSBOyzOVDNHRTs60Jr553TS8k9JAMg1uLs9OL0OwveysIJmfHDycageUqvalhFMAEQ3MQ-rUfCzio0rPPsmCrLQ/s640/2020-03-08_17-02-28.png" width="640" /></a></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;">Notice that the endpoint name no longer contains Microsoft.</span></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div>
<b><span style="font-family: Trebuchet MS, sans-serif;">In PowerShell 7, </span><span style="color: #660000; font-family: Courier New, Courier, monospace;">Get-PSSSionConfiguration </span></b><span style="font-family: Trebuchet MS, sans-serif;"><b>does not show Windows PowerShell endpoints.</b> Even though those endpoints exist, you can't see them in PowerShell 7.</span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;">If you use either </span><span style="color: #660000; font-family: Courier New, Courier, monospace;"><b>Invoke-Command</b></span><span style="font-family: Trebuchet MS, sans-serif;"> or </span><span style="color: #660000; font-family: Courier New, Courier, monospace;"><b>Enter-PSSession</b></span><span style="font-family: Trebuchet MS, sans-serif;">, you can specify a specific endpoint. to use. <b>If you specify no endpoint, then PowerShell remoting uses the value of </b></span><span style="color: #660000; font-family: Courier New, Courier, monospace; font-weight: bold;">$PSSessionConfigurationName</span><span style="font-family: Trebuchet MS, sans-serif; font-weight: bold;">. By default, this is set to</span><span style="color: #660000; font-family: Courier New, Courier, monospace;"><b> http://schemas.microsoft.com/powershell/Microsoft.PowerShell</b></span><span style="font-family: Trebuchet MS, sans-serif;">. So by default, this is the behaviour on the local machine:</span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzgsqV2lxclV7mshUJzYB5SE0H3PbIBZwdwnO9DdGHWAWv9ucuMIoPHIaEB-EayywaCk3LzB1mLnXrB3ADBJ5a2L5CGCsQA-Y9f-3-ynoAWs70914oR2GjE0UJc1ErU9SeK0EglQ/s1600/2020-03-08_17-05-50.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="276" data-original-width="491" height="179" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzgsqV2lxclV7mshUJzYB5SE0H3PbIBZwdwnO9DdGHWAWv9ucuMIoPHIaEB-EayywaCk3LzB1mLnXrB3ADBJ5a2L5CGCsQA-Y9f-3-ynoAWs70914oR2GjE0UJc1ErU9SeK0EglQ/s320/2020-03-08_17-05-50.png" width="320" /></a></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;">Once you create the PowerShell endpoints - you can use them like this:</span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdV_E5UBURftMTkgqNJqWucrDeOBeewLx6rxH2J0W4n2LEaTe69eXMC9xxa1np0_3xzAGbfbsJBLiUnN3XRUnsbBiF-kwIOgYf2KyDwLgYfRolPUqde8hsWknblKijH-bOkC6Pow/s1600/2020-03-08_17-15-46.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="288" data-original-width="802" height="114" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdV_E5UBURftMTkgqNJqWucrDeOBeewLx6rxH2J0W4n2LEaTe69eXMC9xxa1np0_3xzAGbfbsJBLiUnN3XRUnsbBiF-kwIOgYf2KyDwLgYfRolPUqde8hsWknblKijH-bOkC6Pow/s320/2020-03-08_17-15-46.png" width="320" /></a></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;">In most cases, remoting is going to work as with Windows PowerShell. But with differences. </span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;">I am hoping that the inability to see Windows PowerShell endpoints is a bug that can be fixed in 7.1. We'll see.</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<br /></div>
Unknownnoreply@blogger.com0