&lt;?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Articles from April 2019 on PowerShell.org - Welcome Automaters!</title><link>https://powershell.org/articles/2019/04/</link><description>Recent content in Articles from April 2019 on PowerShell.org - Welcome Automaters!</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://powershell.org/articles/2019/04/index.xml" rel="self" type="application/rss+xml"/><item><title>Find-Module, Find-Script – Don't Recreate the Wheel</title><link>https://powershell.org/articles/2019-04-29-find-module-find-script-dont-recreate-the-wheel/</link><guid>https://powershell.org/articles/2019-04-29-find-module-find-script-dont-recreate-the-wheel/</guid><pubDate>Mon, 29 Apr 2019 18:52:07 +0000</pubDate><description>&lt;p&gt;The PowerShell Gallery is a collection of modules and scripts that is community driven to help us automate everyday tasks. Sometimes, we have an idea that could written into a function or script, however, most of the time, someone else had the same idea and published their work to the PowerShell Gallery. There is no need to recreate the wheel and re-write it, use the community to our advantage. We&amp;rsquo;ll take a look at multiple Cmdlets,&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>The PowerShell Gallery is a collection of modules and scripts that is community driven to help us automate everyday tasks. Sometimes, we have an idea that could written into a function or script, however, most of the time, someone else had the same idea and published their work to the PowerShell Gallery. There is no need to recreate the wheel and re-write it, use the community to our advantage. We&rsquo;ll take a look at multiple Cmdlets,</p><p><code>Find-Module</code>,</p><p><code>Find-Script</code>,</p><p><code>Install-Module</code>, and</p><p><code>Install-Script</code>, and find out what each of them provide.</p><p><strong>Find-Module</strong><strong>and Install-Module</strong></p><p><code>Find-Module</code>allows us the</p><p><em>browse</em> the PowerShell Gallery and find if there is a module in the community that has been created. Running</p><p><code>Get-Help Find-Module</code>, we can see there are multiple parameters to use to help narrow our search. For demonstration, we will find the Azure PowerShell (Az) module by Microsoft using the</p><p><code>Find-Module</code>Cmdlet.</p><p>`Get-Help Find-Module
NAME
Find-Module
SYNTAX
Find-Module [[-Name] ] [-MinimumVersion ] [-MaximumVersion ] [-RequiredVersion ] [-AllVersions] [-IncludeDependencies] [-Filter ] [-Tag
] [-Includes {DscResource | Cmdlet | Function | RoleCapability}] [-DscResource ] [-RoleCapability ] [-Command ] [-Proxy ] [-ProxyCredential
] [-Repository ] [-Credential ] []
ALIASES
fimo
REMARKS
Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only partial help.
&ndash; To download and install Help files for the module that includes this cmdlet, use Update-Help.
&ndash; To view the Help topic for this cmdlet online, type: &ldquo;Get-Help Find-Module -Online&rdquo; or
go to<a href="http://go.microsoft.com/fwlink/?LinkID=398574">http://go.microsoft.com/fwlink/?LinkID=398574</a>.
Find-Module -Name Az
Version Name Repository Description</p><hr><p>1.8.0 Az PSGallery Microsoft Azure PowerShell - Cmdlets to manage resources in Azure. This module is compatible with WindowsPowerShell and P&hellip;
`Great. We were able to find the Az module and returned some information about the module: Version, Name, Repository, and Description. But what if we did not know the name of a module we are looking for? The</p><p><code>-Name</code>parameter accepts wildcards for partial searches, we can enter in</p><p><code>Find-Module -Name Az*</code>and will return any module in the gallery that starts with &ldquo;Az&rdquo;. We can also search for DSC Resources using the</p><p><code>Find-Module</code>Cmdlet using the</p><p><code>-Includes DscResource</code>parameter. This will only return DSC Resources available in the PowerShell Gallery</p><p><code>Find-Module -Name xWeb* -Includes DscResource</code>Once we found the module that we want to use, we can install the module using the</p><p><code>Install-Module</code>Cmdlet. This will install the community module in our default module install directory:</p><p><code>C:\Program Files\WindowsPowerShell\Modules</code>or if using PowerShell Core:</p><p><code>C:\Program Files\PowerShell\Modules</code>. Lets take the example above and use it to install the Az Module.</p><p><code>Find-Module -Name Az |Install-Module</code>We can take the</p><p><code>Find-Module</code>Cmdlet and pipe it to the</p><p><code>Install-Module</code>Cmdlet to install the module. But, we also have the ability to install a specific version of a module using the</p><p><code>-RequiredVersion</code>parameter.</p><p><code>Install-Module -Name Az -RequiredVersion 1.7</code>Not using the</p><p><code>-RequiredVersion</code>parameter will install the latest version of the module.</p><p><strong>Note:</strong> Find-Module and Install-Module was introduced in PowerShell version 5.0.</p><p><strong>Find-Script and Install-Script</strong></p><p><code>Find-Script</code>works the same way as</p><p><code>Find-Module</code>, however, instead of finding modules, we are now finding scripts.</p><p><code>Find-Script</code>will return</p><p><code>.ps1</code>scripts in the PowerShell Gallery that could be installed. Lets take a look at an example to find a script and than later on we will install it. The same rules apply when trying to find a script, we can use wildcards in our search to find a certain script.</p><p>`Find-Script -Name Get-*
Version Name Repository Description</p><hr><p>1.4 Get-WindowsAutoPilotInfo PSGallery This script uses WMI to retrieve properties needed by the Microsoft Store for Business to support Windows AutoPilot deplo&hellip;
1.0.0 Get-Quotation PSGallery Get-Quote cmdlet data harvests a/multiple quote(s) from Web outputs into your powershell console
1.0.0 Get-UsersOnlineOnReddit PSGallery Script to web data scrape reddit user trend and pump all the data points script captured from Reddit’s Powershell Communi&hellip;
1.0.4 Get-PacFile PSGallery This script will access updated information to create a PAC file to prioritize Microsoft 365 Urls for&hellip;
1.1.2.7 Get-AzureAutomationDiagnosticRes&hellip; PSGallery Capture diagnostic information for Azure Automation accounts. &hellip;
1.1.0 Get-VMotion PSGallery Report on recent vMotion events in your VMware environment.
1.2.1 Get-RemoteProgram PSGallery This function generates a list by querying the registry and returning the installed programs of a local or remote computer.
1.1 get-uptime PSGallery Get the uptime of the current machine.
1.0.1 Get-InstalledProgram PSGallery Get-InstalledProgram retrieves the programs installed on a local or remote machine. To specify a remote computer, use the&hellip;
0.0.1 Get-LockoutBlame PSGallery Script to get a Windows Event about Locked Accounts, including the host which caused the lockout&hellip;.
0.1.1 get-lastreboot PSGallery Get the last reboot information from multiple machines
1.0 Get-DnsConfiguration PSGallery Retrives primary, secondary, tertiery DNS Servers from on online system using Windows Management Instrimentation.
1.0 Get-Github PSGallery Download a github repository or a gist
1.1 Get-MyIP PSGallery Get your External IP address&hellip;
1.3.5 Get-WindowsUpTime PSGallery Get Windows UpTime StartTime and LocalTime by Wmi on local and remote system
2.9 Get-Parameter PSGallery Lists all the parameters of a command, by ParameterSet, including their aliases, type, etc&hellip;.
2.0 Get-LastLoggedOnUser PSGallery Gets the last not special user to have a loaded profile on a given system.
`We searched for all scripts that start with</p><p><code>Get-*</code>, now lets find the script we want to install:</p><p><code>Join-String</code>Find-Script -Name Join-String
Version Name Repository Description</p><hr><p>1.0 Join-String PSGallery Join String from Array
`Now that we found the scripts, lets install it using the same pipeline. Using the</p><p><code>Install-Script</code>Cmdlet, the script will install in the default script location:</p><p><code>C:\Program Files\WindowsPowerShell\Scripts</code>or if using PowerShell Core:</p><p><code>C:\Program Files\PowerShell\Scripts</code>.</p><p><code>Find-Script -Name Join-String |Install-Script</code>We can still use the</p><p><code>-RequiredVersion</code>parameter if a specified version is required, but using the command above will install the latest.</p><p><code>Find-Module</code>,</p><p><code>Find-Script</code>,</p><p><code>Install-Module</code>, and</p><p><code>Install-Script</code>are great to find and install modules or scripts from the PowerShell Gallery, there is no need to recreate the wheel, (Most of the time). You can also search the PowerShell Gallery by visiting the website</p><p><a href="https://www.powershellgallery.com/">here</a>. When searching for a module or script, the site will show you the command to run in PowerShell to install the module or script.</p><p>Just a reminder that these Cmdlets were introduced in PowerShell version 5.0 and are in the<a href="https://docs.microsoft.com/en-us/powershell/module/powershellget/?view=powershell-6">PowerShellGet</a> module. The links below are Microsoft&rsquo;s documentation for each Cmdlet with examples and other parameters that can be used.</p><p><a href="https://docs.microsoft.com/en-us/powershell/module/powershellget/Find-Module?view=powershell-6%EF%BB%BF">Find-Module</a><br><a href="https://docs.microsoft.com/en-us/powershell/module/powershellget/Install-Module?view=powershell-6%EF%BB%BF">Install-Module</a><br><a href="https://docs.microsoft.com/en-us/powershell/module/powershellget/Find-Script?view=powershell-6">Find-Script<br/><a href="https://docs.microsoft.com/en-us/powershell/module/powershellget/Install-Script?view=powershell-6">Install-Script</a></p><p>pwshliquori</p>
]]></content:encoded></item><item><title>Phenomenal number of ACLs, itty-bitty living space</title><link>https://powershell.org/articles/2019-04-26-phenomenal-number-of-acls-itty-bitty-living-space/</link><guid>https://powershell.org/articles/2019-04-26-phenomenal-number-of-acls-itty-bitty-living-space/</guid><pubDate>Fri, 26 Apr 2019 16:19:53 +0000</pubDate><description>&lt;p&gt;I recently had a need to backup file and folder ACLs for a client that would then need to restore them to their original objects following a hardware upgrade that would wipe them out. Easy enough, but the catch was that there was 1.5 million of them. Fortunately, getting ACLs in PowerShell is easy.&lt;/p&gt;
&lt;p&gt;`PS &amp;gt; Get-Acl -Path somefile.txt
Directory: C:&lt;br&gt;
Path Owner Access&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;somefile.txt BUILTIN\Administrators BUILTIN\Administrators Allow&amp;hellip;
`See?&lt;/p&gt;
&lt;p&gt;Now, if you needed multiple ACLs, say, all 1.5 million of them on a file share, you could use &lt;strong&gt;Get-ChildItem&lt;/strong&gt; to feed files and folders to &lt;strong&gt;Get-Acl&lt;/strong&gt;. But then what? &lt;strong&gt;Export-Clixml&lt;/strong&gt; is a generally great way to convert a PowerShell object to XML and save it to file.&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>I recently had a need to backup file and folder ACLs for a client that would then need to restore them to their original objects following a hardware upgrade that would wipe them out. Easy enough, but the catch was that there was 1.5 million of them. Fortunately, getting ACLs in PowerShell is easy.</p><p>`PS &gt; Get-Acl -Path somefile.txt
Directory: C:<br>
Path Owner Access</p><hr><p>somefile.txt BUILTIN\Administrators BUILTIN\Administrators Allow&hellip;
`See?</p><p>Now, if you needed multiple ACLs, say, all 1.5 million of them on a file share, you could use<strong>Get-ChildItem</strong> to feed files and folders to<strong>Get-Acl</strong>. But then what?<strong>Export-Clixml</strong> is a generally great way to convert a PowerShell object to XML and save it to file.</p><p><code>PS &gt; Get-Acl -Path somefile.txt | Export-Clixml -Path AclBackup.ps1xml</code>You then get an ugly monstrosity that looks like this.</p><p><img src="https://powershell.org/wp-content/uploads/2019/04/image.png" alt=""/><p>In my case, there&rsquo;s a serious problem with this approach. Ballpark 100 lines per ACL x 1.5 million filesystem objects = 150 million lines of backup data, and my small test on several thousand files and folders was already about 32MB on disk. In production, it would balloon to a hefty size and this needed to run on a server with 3.5GB of RAM and space constraints. Yeah&hellip; I&rsquo;m not offering that as a solution to anybody.</p><p>Luckily, we can do a little dotnet black magic to trim this down to something much more manageable. Thanks to sk82jack and Chris Dent in the PowerShell Discord, I learned that the<a href="https://docs.microsoft.com/en-us/windows/desktop/secauthz/security-descriptor-definition-language-for-conditional-aces-">SDDL</a> is the only component that&rsquo;s really necessary for recreating the ACL object. They look like this:</p><p><code>O:BAG:S-1-5-21-1192226125-608885206-469304335-1001D:AI(A;ID;FA;;;BA)(A;ID;FA;;;SY)(A;ID;0x1200a9;;;BU)(A;ID;0x1301bf;;;AU)</code>File ACLs are<strong>[System.Security.AccessControl.FileSecurity]</strong> type objects and folder ACLs are<strong>[System.Security.AccessControl.DirectorySecurity]</strong> type objects.</p><p>`PS &gt; [System.Security.AccessControl.FileSecurity]::new()
Path Owner Access</p><hr><p>`Instantiating one of these just gives us a blank object, but we can feed the SDDL as a string to the<strong>SetSecurityDescriptorSddlForm()</strong> method in order to populate it.</p><p>`PS &gt; $a = [System.Security.AccessControl.FileSecurity]::new()
PS &gt; $a.SetSecurityDescriptorSddlForm(&lsquo;O:BAG:S-1-5-21-1192226125-608885206-469304335-1001D:AI(A;ID;FA;;;BA)(A;ID;FA;;;SY)(A;ID;0x1200a9;;;BU)(A;ID;0x1301bf;;;AU)&rsquo;)
PS &gt; $a
Path Owner Access</p><hr><pre><code> NT SERVICE\TrustedInstaller NT AUTHORITY\SYSTEM Allow Modify, Synchronize...</code></pre><p>`I haven&rsquo;t seen a way to fill in the path but that&rsquo;s easily worked around. Armed with this information, I would only need to backup the full path of each object, whether it is a file or a folder, and the SDDL.</p><p>`Get-ChildItem -Path C:\apps -Recurse | Foreach-Object {
[pscustomobject]@{
Path = $<em>.Fullname
IsContainer = $</em>.PSIsContainer
Sddl = $(Get-Acl -Path $_.Fullname).Sddl
}
}
Path IsContainer Sddl</p><hr><p>C:\apps\aclbackup.ps1xml False O:S-1-5-21-1192226125-608885206-469304335&hellip;
C:\apps\az_tenant2tenant.ps1 False O:BAG:S-1-5-21-1192226125-608885206-46930&hellip;
C:\apps\bb_saml_resp_success.xml False O:S-1-5-21-1192226125-608885206-469304335&hellip;
C:\apps\somefile.txt False O:S-1-5-21-1192226125-608885206-469304335&hellip;
C:\apps\testvnet.json False O:BAG:S-1-5-21-1192226125-608885206-46930&hellip;
`Now we&rsquo;re getting somewhere. Flat objects like this will export nicely to CSV, which would be significantly smaller on disk than the ps1xml we started with. When I run the code above against a directory tree with about 56k objects and pipe it to<strong>Export-Csv</strong>, I end up with a 16MB CSV. Some PowerShell napkin math to double-check this&hellip;</p><p><code>PS &gt; 16MB / 56000 299.593142857143 # Just shy of 300 bytes per ACL PS &gt; (300 * 1500000) / 1MB # Per ACL size by the number of ACLs, converted to MBs 429.153442382813</code>&hellip; So around 430MB. That sounds like a much more reasonable backup size to me and it won&rsquo;t chew through what little RAM I have to work with. If we went with<strong>Export-Clixml</strong>, it would have ended up around 8GB, taken significantly longer to run, and probably would have crashed.</p><p>So how would we restore these?</p><p><code>$ACLs = Import-Csv -Path AclsBackup.csv foreach ($ACL in $ACLs) { switch ($ACL.IsContainer) { $true { $AclObj = [System.Security.AccessControl.DirectorySecurity]::new() $AclObj.SetSecurityDescriptorSddlForm($ACL.Sddl) Set-Acl -Path $ACL.Path -AclObject $AclObj } $false { $AclObj = [System.Security.AccessControl.FileSecurity]::new() $AclObj.SetSecurityDescriptorSddlForm($ACL.Sddl) Set-Acl -Path $ACL.Path -AclObject $AclObj } } }</code>And simple as that the ACLs right back where they came from.</p>
]]></content:encoded></item><item><title>ICYMI: PowerShell Week of 26-April-2019</title><link>https://powershell.org/articles/2019-04-26-icymi-powershell-week-of-26-april-2019/</link><guid>https://powershell.org/articles/2019-04-26-icymi-powershell-week-of-26-april-2019/</guid><pubDate>Fri, 26 Apr 2019 15:00:53 +0000</pubDate><description>&lt;p&gt;Topics include building functions for cleaning your $PATH, xplat GUIs with Core, and the EXO module makes its way to the Cloud Shell.&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>Topics include building functions for cleaning your $PATH, xplat GUIs with Core, and the EXO module makes its way to the Cloud Shell.</p><p>Special thanks to Robin Dadswell, Prasoon Karunan, and Mark Roloff.</p><h6 id="introducing-pscvss-a-powershell--powershell-core-module-to-calculate-a-cvss-score" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190426.md#introducing-pscvss-a-powershell--powershell-core-module-to-calculate-a-cvss-score"/><a href="https://www.secopshub.com/t/introducing-pscvss-a-powershell-powershell-core-module-to-calculate-a-cvss-score/743"><em>Introducing PSCVSS: A PowerShell &amp; PowerShell Core Module to calculate a CVSS Score</em></a><a class="ps-heading-anchor" href="#introducing-pscvss-a-powershell--powershell-core-module-to-calculate-a-cvss-score" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Josh Rickard on April 19th</p><p>In the security arena? Being able to locally calculate CVSS scores might be pretty handy for you, then.</p><h6 id="powershell-way-to-get-all-information-about-office-365-service-health" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190426.md#powershell-way-to-get-all-information-about-office-365-service-health"/><a href="https://evotec.xyz/powershell-way-to-get-all-information-about-office-365-service-health/"><em>PowerShell way to get all information about Office 365 Service Health</em></a><a class="ps-heading-anchor" href="#powershell-way-to-get-all-information-about-office-365-service-health" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Przemyslaw Klys on April 22nd</p><p>The title alone doesn&rsquo;t do much justice to how cool this is. Przemyslaw&rsquo;s new module pulls the service health out and fits it nicely into other visualization tools that he&rsquo;s published.</p><h6 id="more-powershell-adventures-in-cleaning-your-path" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190426.md#more-powershell-adventures-in-cleaning-your-path"/><a href="https://jdhitsolutions.com/blog/powershell/6700/more-powershell-adventures-in-cleaning-your-path/"><em>More PowerShell Adventures in Cleaning Your Path</em></a><a class="ps-heading-anchor" href="#more-powershell-adventures-in-cleaning-your-path" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Jeffrey Hicks on April 24th</p><p>Follow along with Jeff as he walks you through building a few functions that can help you learn a little .NET and how to implement the<em>WhatIf</em> switch.</p><h6 id="building-cross-platform-wpf-style-applications-in-powershell-core" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190426.md#building-cross-platform-wpf-style-applications-in-powershell-core"/><a href="https://ironmansoftware.com/building-cross-platform-wpf-style-applications-in-powershell-core/"><em>Building Cross-Platform WPF-Style Applications in PowerShell Core</em></a><a class="ps-heading-anchor" href="#building-cross-platform-wpf-style-applications-in-powershell-core" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Adam Driscoll on April 23rd</p><p>Xplatform GUIs are making their way to PS Core. Leveraging the Avalonia project, Adam&rsquo;s latest PowerShell Pro Tools update opens the door to creating XAML windows.</p><h6 id="customizing-the-title-bar-of-your-powershell-console-window" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190426.md#customizing-the-title-bar-of-your-powershell-console-window"/><a href="https://sid-500.com/2019/04/23/powershell-customizing-the-title-bar-of-your-powershell-console-window/"><em>Customizing the Title Bar of your PowerShell Console Window</em></a><a class="ps-heading-anchor" href="#customizing-the-title-bar-of-your-powershell-console-window" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Patrick Gruenauer on April 23rd</p><p>Want a little personal branding for presentations? Maybe toss something fun or uplifting into your shell&rsquo;s window? Patrick has you covered.</p><h6 id="tweet-of-the-week" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190426.md#tweet-of-the-week"/><a href="https://twitter.com/maertend33/status/1121103069867986944"><em>Tweet of the Week</em></a><a class="ps-heading-anchor" href="#tweet-of-the-week" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>Making the Azure Cloud Shell even more appealing, the Exchange Online module is now available there.</p><h6 id="youtube-powershell-universal-dashboard-with-adam-driscoll" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190426.md#youtube-powershell-universal-dashboard-with-adam-driscoll"/><a href="https://www.youtube.com/watch?v=5LWXrgstfe8"><em>Youtube: Powershell Universal Dashboard with Adam Driscoll</em></a><a class="ps-heading-anchor" href="#youtube-powershell-universal-dashboard-with-adam-driscoll" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>Speaking at the Austin PSUG, Adam gives a rundown on the Universal Dashboard.</p>]]></content:encoded></item><item><title>Azure DevOps – Enable "Allow scripts to access the OAuth token" using PowerShell</title><link>https://powershell.org/articles/2019-04-20-azure-devops-enable-allow-scripts-to-access-the-oauth-token-using-powershell/</link><guid>https://powershell.org/articles/2019-04-20-azure-devops-enable-allow-scripts-to-access-the-oauth-token-using-powershell/</guid><pubDate>Sat, 20 Apr 2019 23:20:30 +0000</pubDate><description>&lt;p&gt;Azure DevOps allows us to run custom scripts to help our software and infrastructure get delivered quickly. There are times that the scripts run without an issue, however, sometimes there is a need to invoke the Azure DevOps Rest API in the release pipeline to get our scripts running. Sure, you can create a script invoking the API, authenticating with Azure DevOps with your personal access token and should work, but there is a better solution.&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>Azure DevOps allows us to run custom scripts to help our software and infrastructure get delivered quickly. There are times that the scripts run without an issue, however, sometimes there is a need to invoke the Azure DevOps Rest API in the release pipeline to get our scripts running. Sure, you can create a script invoking the API, authenticating with Azure DevOps with your personal access token and should work, but there is a better solution.</p><p>Allowing scripts to access the OAuth token authenticates the script with the</p><p><code>System.AccessToken</code>variable, which runs as the Project Collection Build Service, a built-in service account in Azure DevOps. Today, we will be taking a look on how to enable this feature using PowerShell.</p><p>Since the feature needs to be enabled per release definition, the first item we need to find is the definitionId of the release definition. This can be found by using the Rest API or in the URL when clicking on the release definition in Azure DevOps. Since we are using PowerShell, let’s try it, but first, be sure to have your personal access token handy. The below commands are for my own blog organization, please substitute with your organization and project name. There will be a function provided at the end that parameterizes these values.</p><p><code>$Params = @{ Uri = "https://vsrm.dev.azure.com/pwshliquori-blog/blog/_apis/release/definitions/1?api-version=5.0" Headers = @{ Authorization = "Basic $PersonalAccessToken" } } $Def = Invoke-RestMethod @Params</code>Let’s take a look at the command:</p><ul><li><p>$Params: A hash table we will splat when we are ready to run the command.</p></li><li><p>$Params.Uri: The components needed to get the release definitions.</p></li><li><p>pwshliquori-blog: Organization name.</p></li><li><p>blog: Project name.</p></li><li><p>_apis: Standard for calling the rest API.</p></li><li><p>release: The area of the API call.</p></li><li><p>definitions: The resource of the API call.</p></li><li><p>api-version=5.0: The latest version of the API.</p></li><li><p>$Headers: Authorization header using your base 64 encoded personal access token.</p></li><li><p>Invoke-RestMethod @Params: Invokes the Rest API splatting the $Params hashtable.</p></li></ul><p>The command should return the release definition in the project with definitionId 1. Now we need to dig down and find the property needed to enable, in this case: “enableAccessToken.”</p><p>The &ldquo;enableAccessToken&rdquo; property is set to false by default, lets find and set it to true:</p><p><code>$Def.environments.deployPhases.deploymentInput parallelExecution : @{parallelExecutionType=none} skipArtifactsDownload : False artifactsDownloadInput : @{downloadInputs=System.Object[]} queueId : 3 demands : {} enableAccessToken : False timeoutInMinutes : 0 jobCancelTimeoutInMinutes : 1 condition : succeeded() overrideInputs : $Def.environments.deployPhases.deploymentInput.enableAccessToken = $true $Def.environments.deployPhases.deploymentInput parallelExecution : @{parallelExecutionType=none} skipArtifactsDownload : False artifactsDownloadInput : @{downloadInputs=System.Object[]} queueId : 3 demands : {} enableAccessToken : True timeoutInMinutes : 0 jobCancelTimeoutInMinutes : 1 condition : succeeded() overrideInputs :</code>Now that we set the “enableAccessToken” to true, we need to update the release definition with the changed value. To do this, we need to convert the $Def variable to JSON format and set the ContentType to application/json.</p><p><code>$Body = ConvertTo-Json -InputObject $Def -Depth 10 $Params = @{ Uri = "https://dev.azure.com/pwshliquori-blog/blog/_apis/release/definitions/1?api-version=5.0" Headers = @{ Authorization = "Basic $ConvertToBase64" } Body = $Body ContentType = 'application/json Method = 'Put' } Invoke-RestMethod @Params</code>The body needs to contain the entire release definition with the updated “enableAccessToken” property. After running the command, we can now utilize the</p><p><code>System.AccessToken</code>to run scripts and processes using OAuth authentication that uses the Project Collection Build Service account. By using PowerShell, we can now turn the commands above into a function to automate the process of enabling this feature.</p><p><code>function Enable-AzureDevOpsReleaseDefinitionOAuthToken { [CmdletBinding()] param ( [Parameter(Mandatory, ValueFromPipeline, Position = 0)] [string]$OrganizationName, [Parameter(Mandatory, ValueFromPipeline, Position = 1)] [string]$ProjectName, [Parameter(Mandatory, Position = 2)] [string]$ReleaseDefinitionId, [Parameter(Position = 3)] [string]$PersonalAccessToken ) Begin { $BasicAuth = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f '', $PersonalAccessToken))) } Process { Try { $Params = @{ Uri = "https://vsrm.dev.azure.com/$OrganizationName/$ProjectName/_apis/release/definitions/$($ReleaseDefinitionId)?api-version=5.0" Headers = @{ Authorization = "Basic $BasicAuth" } } $ReleaseDefinition = Invoke-RestMethod @Params $ReleaseDefinition.environments |ForEach-Object { $_.deployPhases.deploymentinput.enableAccessToken = $true } $JsonObject = foreach ($Definition in $ReleaseDefinition) { ConvertTo-Json -InputObject $Definition -Depth 10 } $Params.Method = 'Put' $Params.ContentType = 'application/json' foreach ($Json in $JsonObject) { $Params.Body = $Json Invoke-RestMethod @Params } } Catch { throw $_ } } }</code>The function will enable the OAuth token for all environments in the given release definition, which gives us the option to use the</p><p><code>System.AccessToken</code>variable. This is handy when we want to run custom scripts without using our own personal access token. Another example is if we needed to create an annotated tag for a release and need to use the Build Service Account to tag the release instead of a release administrators personal access token.</p><p>For purposes of this post, I have provided one function, but this should be split into two separate functions. One function to get the release definition, and then next to enable the OAuth token, taking an</p><p><code>InputObject</code>parameter. As the legendary Don Jones states &ldquo;A function is a tool that should do one thing really well.&rdquo;</p><p>To find more information on using the Rest API, visit Microsoft documentation on the Azure DevOps Rest API.</p><p><a href="https://docs.microsoft.com/en-us/rest/api/azure/devops/?view=azure-devops-rest-5.0">https://docs.microsoft.com/en-us/rest/api/azure/devops/?view=azure-devops-rest-5.0</a></p><p>pwshliquori</p>
]]></content:encoded></item><item><title>Get-Command – One of the best Cmdlets besides Get-Help</title><link>https://powershell.org/articles/2019-04-19-get-command-one-of-the-best-cmdlets-besides-get-help/</link><guid>https://powershell.org/articles/2019-04-19-get-command-one-of-the-best-cmdlets-besides-get-help/</guid><pubDate>Fri, 19 Apr 2019 16:59:06 +0000</pubDate><description>&lt;p&gt;So laying on the sofa, sick, bored out of my mind, what better way to spend my time then writing a blog post about&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Get-Command &lt;/code&gt;. The&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Get-Command &lt;/code&gt;Cmdlet is apart of the Microsoft.PowerShell.Core module, it was introduced in PowerShell version 1.0 and is one of the most useful Cmdlets to find a command you are looking for. It has a variety of parameters that allow you to search for a command by using a combination of parameters or just using&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>So laying on the sofa, sick, bored out of my mind, what better way to spend my time then writing a blog post about</p><p><code>Get-Command</code>. The</p><p><code>Get-Command</code>Cmdlet is apart of the Microsoft.PowerShell.Core module, it was introduced in PowerShell version 1.0 and is one of the most useful Cmdlets to find a command you are looking for. It has a variety of parameters that allow you to search for a command by using a combination of parameters or just using</p><p><code>Get-Command</code>on its own. Go ahead and run</p><p><code>Get-Command</code>in your console before continuing with this post. As you can see, it returns all commands that are available in your PowerShell session. Later on, we will go through several example on how we can leverage the parameters to find specifics commands.</p><p>Lets start with a basic example and then build on it to get a specific command,</p><p><code>Get-ADUser</code>. First, lets get all of the command that are already imported into our PowerShell session.</p><p>`Get-Command -ListImported
CommandType Name Version Source</p><hr><p>Function New-HiiDistributionGroup 1.0.0.0 ExchangeTools
Function New-HiiExchangeSession 1.0.0.0 ExchangeTools
Function New-HiiMailContact 1.0.0.0 ExchangeTools
Function Add-HiiSmtpEmailAddress 1.0.0.0 ExchangeTools
Function New-HiiMailbox 1.0.0.0 ExchangeTools
Function New-HiiUserMailboxDistributionList 1.0.0.0 ExchangeTools
Function Get-HiiSmtpEmailAddress 1.0.0.0 ExchangeTools
Function Add-HiiDistributionGroupMember 1.0.0.0 ExchangeTools
Function Remove-HiiSmtpEmailAddress 1.0.0.0 ExchangeTools
Function Export-HiiMailboxToPST 1.0.0.0 ExchangeTools
Cmdlet Remove-Job 3.0.0.0 Microsoft.PowerShell.Core
Cmdlet Register-PSSessionConfiguration 3.0.0.0 Microsoft.PowerShell.Core
Cmdlet Get-Help 3.0.0.0 Microsoft.PowerShell.Core
Cmdlet Remove-Module 3.0.0.0 Microsoft.PowerShell.Core
Cmdlet Out-Null 3.0.0.0 Microsoft.PowerShell.Core
Cmdlet Receive-Job 3.0.0.0 Microsoft.PowerShell.Core
Cmdlet Receive-PSSession 3.0.0.0 Microsoft.PowerShell.Core
Cmdlet Register-ArgumentCompleter 3.0.0.0 Microsoft.PowerShell.Core
Cmdlet Get-History 3.0.0.0 Microsoft.PowerShell.Core
Cmdlet Get-Job 3.0.0.0 Microsoft.PowerShell.Core
`The output does not have any Cmdlets from the ActiveDirectory module we need to find the</p><p><code>GetADUser</code>. If you have RSAT Tools installed, import the module using</p><p><code>Import-Module ActiveDirectory</code>and re-run</p><p><code>Get-Command -ListImported</code>. As you can see now, a list of Active Directory Cmdlets are available. We can now start getting more complex to find</p><p><code>Get-ADUser</code>.</p><p>Lets get limit the scope of our command to get only the ActiveDirectory module Cmdlets that are available.</p><p>`Get-Command -Module ActiveDirectory
CommandType Name Version Source</p><hr><p>Cmdlet Add-ADCentralAccessPolicyMember 1.0.1.0 activedirectory
Cmdlet Add-ADComputerServiceAccount 1.0.1.0 activedirectory
Cmdlet Add-ADDomainControllerPasswordReplicationPolicy 1.0.1.0 activedirectory
Cmdlet Add-ADFineGrainedPasswordPolicySubject 1.0.1.0 activedirectory
Cmdlet Add-ADGroupMember 1.0.1.0 activedirectory
Cmdlet Add-ADPrincipalGroupMembership 1.0.1.0 activedirectory
Cmdlet Add-ADResourcePropertyListMember 1.0.1.0 activedirectory
Cmdlet Clear-ADAccountExpiration 1.0.1.0 activedirectory
Cmdlet Clear-ADClaimTransformLink 1.0.1.0 activedirectory
Cmdlet Disable-ADAccount 1.0.1.0 activedirectory
Cmdlet Disable-ADOptionalFeature 1.0.1.0 activedirectory
Cmdlet Enable-ADAccount 1.0.1.0 activedirectory
Cmdlet Enable-ADOptionalFeature 1.0.1.0 activedirectory
Cmdlet Get-ADAccountAuthorizationGroup 1.0.1.0 activedirectory
Cmdlet Get-ADAccountResultantPasswordReplicationPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADAuthenticationPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADAuthenticationPolicySilo 1.0.1.0 activedirectory
Cmdlet Get-ADCentralAccessPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADCentralAccessRule 1.0.1.0 activedirectory
Cmdlet Get-ADClaimTransformPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADClaimType 1.0.1.0 activedirectory
Cmdlet Get-ADComputer 1.0.1.0 activedirectory
`Now we filtered only the ActiveDirectory module and can now filter down even more.</p><p><code>Get-Command</code>has a parameter</p><p><code>-Verb</code>that allows us to filter by using the verb of the Cmdlet (e.g. Get, Set, Import, Reset). Lets filter by verb</p><p><code>Get</code>and view the output.</p><p>`Get-Command -Module ActiveDirectory -Verb Get
CommandType Name Version Source</p><hr><p>Cmdlet Get-ADAccountAuthorizationGroup 1.0.1.0 activedirectory
Cmdlet Get-ADAccountResultantPasswordReplicationPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADAuthenticationPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADAuthenticationPolicySilo 1.0.1.0 activedirectory
Cmdlet Get-ADCentralAccessPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADCentralAccessRule 1.0.1.0 activedirectory
Cmdlet Get-ADClaimTransformPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADClaimType 1.0.1.0 activedirectory
Cmdlet Get-ADComputer 1.0.1.0 activedirectory
Cmdlet Get-ADComputerServiceAccount 1.0.1.0 activedirectory
Cmdlet Get-ADDCCloningExcludedApplicationList 1.0.1.0 activedirectory
Cmdlet Get-ADDefaultDomainPasswordPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADDomain 1.0.1.0 activedirectory
Cmdlet Get-ADDomainController 1.0.1.0 activedirectory
Cmdlet Get-ADDomainControllerPasswordReplicationPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADDomainControllerPasswordReplicationPolicy&hellip; 1.0.1.0 activedirector
`Great! we now have all Cmdlets that start with the verb</p><p><code>Get</code>. Lets keep building, another parameter</p><p><code>-Noun</code>. We know the prefix for most ActiveDirectory Cmdlets start with AD, so lets use the noun User and see what the output is.</p><p>`Get-Command -Module ActiveDirectory -Verb Get -Noun *User
CommandType Name Version Source</p><hr><p>Cmdlet Get-ADUser 1.0.1.0 activedirectory
`Success! We found exactly the command we needed to. But did you notice the</p><p><code>*</code>character in the noun parameter? This is because we know the prefix is</p><p><code>AD</code>and the noun parameter acts as a filter, this tells PowerShell to find anything that has User in the noun. You can do the same for the parameter</p><p><code>-Verb</code>.</p><p>So now what? We found the command, but what else can we do with</p><p><code>Get-Command</code>. Besides just getting the command, we can get syntax, command info, or search by parameter type or parameter name. Lets see the syntax of</p><p><code>Get-ADUser</code>so we can better understand what it does.</p><p><code>Get-Command -Module ActiveDirectory -Verb Get -Noun *User -Syntax Get-ADUser -Filter [-AuthType ] [-Credential ] [-Properties ] [-ResultPageSize ] [-ResultSetSize ] [-SearchBase ] [-SearchScope ] [-Server ] [] Get-ADUser [-Identity] [-AuthType ] [-Credential ] [-Partition ] [-Properties ] [-Server ] [] Get-ADUser -LDAPFilter [-AuthType ] [-Credential ] [-Properties ] [-ResultPageSize ] [-ResultSetSize ] [-SearchBase ] [-SearchScope ] [-Server ] []</code>We can now see the parameters and parameter types of each. This is a great way to understand how the Cmdlet works and how we can use it in our own code.</p><p>Now that we built our command to find just the</p><p><code>Get-ADUser</code>and get the syntax. Lets look at another example that searches for a certain parameter name</p><p><code>Identity</code>. Using the parameter</p><p><code>ParameterName</code>will allow us to filter through Cmdlets in the ActiveDirectory module that has an</p><p><code>-Identity</code>parameter.</p><p>`Get-Command -Module ActiveDirectory -ParameterType IdentityCommandType Name Version Source</p><hr><p>Cmdlet Add-ADCentralAccessPolicyMember 1.0.1.0 activedirectory
Cmdlet Add-ADComputerServiceAccount 1.0.1.0 activedirectory
Cmdlet Add-ADDomainControllerPasswordReplicationPolicy 1.0.1.0 activedirectory
Cmdlet Add-ADFineGrainedPasswordPolicySubject 1.0.1.0 activedirectory
Cmdlet Add-ADGroupMember 1.0.1.0 activedirectory
Cmdlet Add-ADPrincipalGroupMembership 1.0.1.0 activedirectory
Cmdlet Add-ADResourcePropertyListMember 1.0.1.0 activedirectory
Cmdlet Clear-ADAccountExpiration 1.0.1.0 activedirectory
Cmdlet Clear-ADClaimTransformLink 1.0.1.0 activedirectory
Cmdlet Disable-ADAccount 1.0.1.0 activedirectory
Cmdlet Disable-ADOptionalFeature 1.0.1.0 activedirectory
Cmdlet Enable-ADAccount 1.0.1.0 activedirectory
Cmdlet Enable-ADOptionalFeature 1.0.1.0 activedirectory
Cmdlet Get-ADAccountAuthorizationGroup 1.0.1.0 activedirectory
Cmdlet Get-ADAccountResultantPasswordReplicationPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADAuthenticationPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADAuthenticationPolicySilo 1.0.1.0 activedirectory
Cmdlet Get-ADCentralAccessPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADCentralAccessRule 1.0.1.0 activedirectory
Cmdlet Get-ADClaimTransformPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADClaimType 1.0.1.0 activedirectory
Cmdlet Get-ADComputer 1.0.1.0 activedirectory
Cmdlet Get-ADComputerServiceAccount 1.0.1.0 activedirectory
Cmdlet Get-ADDefaultDomainPasswordPolicy 1.0.1.0 activedirectory
Cmdlet Get-ADDomain 1.0.1.0 activedirectory
`We have found all of the command that have a parameter name of</p><p><code>Identity</code>. For purposes, there are a limited set listed above, the actual total number of Cmdlets that have the parameter of</p><p><code>Identity</code>is 117.</p><p>The last two parameters to take a look at are the</p><p><code>-Name</code>and</p><p><code>-ShowCommandInfo</code>parameters. If we already know the Cmdlet name and want to find which module it is in, we can use the</p><p><code>-Name</code>parameter and view the Source.</p><p>`Get-Command -Name Get-ADUser
CommandType Name Version Source</p><hr><p>Cmdlet Get-ADUser 1.0.1.0 activedirectory
`The command found the Cmdlet and is found in the ActiveDirectory module. The final parameter will build on the previous example, but we will add the</p><p><code>-ShowCommandInfo</code>parameter. The</p><p><code>-ShowCommandInfo</code>show the information pertaining to the command you a attempting to get.</p><p><code>Get-Command -Name Get-ADUser -ShowCommandInfo Name : Get-ADUser ModuleName : activedirectory Module : @{Name=activedirectory} CommandType : Cmdlet Definition : Get-ADUser -Filter [-AuthType ] [-Credential ] [-Properties ] [-ResultPageSize ] [-ResultSetSize ] [-SearchBase ] [-SearchScope ] [-Server ] [] Get-ADUser [-Identity] [-AuthType ] [-Credential ] [-Partition ] [-Properties ] [-Server ] [] Get-ADUser -LDAPFilter [-AuthType ] [-Credential ] [-Properties ] [-ResultPageSize ] [-ResultSetSize ] [-SearchBase ] [-SearchScope ] [-Server ] [] ParameterSets : {@{Name=Filter; IsDefault=True; Parameters=System.Management.Automation.PSObject[]}, @{Name=Identity; IsDefault=False; Parameters=System.Management.Automation.PSObject[]}, @{Name=LdapFilter; IsDefault=False; Parameters=System.Management.Automation.PSObject[]}}</code>Now we can see all of the information in the</p><p><code>Get-ADUser</code>Cmdlet, including syntax information.</p><p>We took a look at multiple examples of the</p><p><code>Get-Command</code>Cmdlet that can help us build tools in our scripts and module. It is a very help tool and that is why, (IMHO), it is one of the best Cmdlets to use besides</p><p><code>Get-Help</code>. To find out more information about</p><p><code>Get-Command</code>view Microsoft&rsquo;s documentation.</p><p><a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/get-command?view=powershell-6">Get-Command</a></p><p>Note: At the time of writing this post, PowerShell is in version 6. The</p><p><code>-ShowCommandInfo</code>parameter was introduced in PowerShell version 5.0.</p><p>Update: Get-Command was introduced in PowerShell v1.0, not 3.0. Thanks to Ryan Yates for the correction. Microsoft&rsquo;s docs on Get-Command only goes back to v3.0.</p><p>pwshliquori</p>
]]></content:encoded></item><item><title>ICYMI: PowerShell Week of 19-April-2019</title><link>https://powershell.org/articles/2019-04-19-icymi-powershell-week-of-19-april-2019/</link><guid>https://powershell.org/articles/2019-04-19-icymi-powershell-week-of-19-april-2019/</guid><pubDate>Fri, 19 Apr 2019 15:00:35 +0000</pubDate><description>&lt;p&gt;Topics include DSC, Pester, validation attributes, and Azure AD.&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>Topics include DSC, Pester, validation attributes, and Azure AD.</p><p>Special thanks to Robin Dadswell and Mark Roloff.</p><h6 id="defensive-powershell" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190419.md#defensive-powershell"/><a href="https://medium.com/@cjkuech/defensive-powershell-with-validation-attributes-8e7303e179fd"><em>Defensive PowerShell</em></a><a class="ps-heading-anchor" href="#defensive-powershell" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Christopher Kuech on April 13th</p><p>Did you know that you can use validation attributes outside of a<em>param</em> block? Mind. Blown.</p><h6 id="desired-state-configuration-dsc--get-started" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190419.md#desired-state-configuration-dsc--get-started"/><a href="https://nedimmehic.org/2019/04/16/desired-state-configuration-dsc-get-started/"><em>Desired State Configuration (DSC) – Get Started</em></a><a class="ps-heading-anchor" href="#desired-state-configuration-dsc--get-started" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Nedim Mehic on April 16th</p><p>If you&rsquo;re still looking to get your feet wet with DSC, this is one of the more detailed intros we&rsquo;ve run across and is well worth your time.</p><h6 id="get-users-from-azure-ad-with-a-large-number-of-registered-devices" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190419.md#get-users-from-azure-ad-with-a-large-number-of-registered-devices"/><a href="https://byteben.com/bb/get-users-from-azure-ad-with-a-large-number-of-registered-devices/"><em>Get Users from Azure AD with a large number of Registered Devices</em></a><a class="ps-heading-anchor" href="#get-users-from-azure-ad-with-a-large-number-of-registered-devices" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Ben Whitmore on April 16th</p><p>A quick and easy way to report on the number of registered devices for multiple users, rather than one at a time.</p><h6 id="tweet-of-the-week" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190419.md#tweet-of-the-week"/><a href="https://twitter.com/ADTipsTricks/status/664261417588146176"><em>Tweet of the Week</em></a><a class="ps-heading-anchor" href="#tweet-of-the-week" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>Here&rsquo;s a fun graphical cheatsheet for various PowerShell concepts.</p><h6 id="youtube-socal-powershell-kevin-marquette-unplugged" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190419.md#youtube-socal-powershell-kevin-marquette-unplugged"/><a href="https://youtu.be/hRhFwDnneJw"><em>Youtube: SoCal PowerShell: Kevin Marquette Unplugged</em></a><a class="ps-heading-anchor" href="#youtube-socal-powershell-kevin-marquette-unplugged" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>Kevin Marquette talks some shop before jumping into debugging with VSCode.</p><h6 id="youtube-pester-why-you-should--be-using-pester-with-jonathan-moss" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190419.md#youtube-pester-why-you-should--be-using-pester-with-jonathan-moss"/><a href="https://www.youtube.com/watch?v=FP7W4kP7Dig"><em>Youtube: Pester: Why You Should -Be Using Pester with Jonathan Moss</em></a><a class="ps-heading-anchor" href="#youtube-pester-why-you-should--be-using-pester-with-jonathan-moss" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>From the Raleigh Triangle User Group, Jonathon Moss will sell you on using Pester.</p>]]></content:encoded></item><item><title>Learn To Use Verbose Output Streams In Your Pester Tests</title><link>https://powershell.org/articles/2019-04-18-learn-to-use-verbose-output-streams-in-your-pester-tests/</link><guid>https://powershell.org/articles/2019-04-18-learn-to-use-verbose-output-streams-in-your-pester-tests/</guid><pubDate>Thu, 18 Apr 2019 19:51:31 +0000</pubDate><description>&lt;p&gt;I&amp;rsquo;m going to file this under &amp;ldquo;Either I&amp;rsquo;m a genius, or there&amp;rsquo;s a much better way and everyone knows it except for me.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I recently began adding a suite of Pester tests to one of my projects and I found myself needing to mock some unit tests against a particular function that would modify a variable based on the parameter specified. Since all the functions I write nowadays are considered advanced functions (and yours should be too, they&amp;rsquo;re free!), I discovered a nice way to test the function&amp;rsquo;s actions using the&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>I&rsquo;m going to file this under &ldquo;Either I&rsquo;m a genius, or there&rsquo;s a much better way and everyone knows it except for me.&rdquo;</p><p>I recently began adding a suite of Pester tests to one of my projects and I found myself needing to mock some unit tests against a particular function that would modify a variable based on the parameter specified. Since all the functions I write nowadays are considered advanced functions (and yours should be too, they&rsquo;re free!), I discovered a nice way to test the function&rsquo;s actions using the</p><p><code>-Verbose</code>stream output.</p><blockquote/><blockquote><p>Full source code for these examples is available on the Pester branch of my KaceSMA project<a href="https://github.com/ArtisanByteCrafter/KaceSMA/tree/pester">on GitHub</a></p></blockquote><h2 id="a-real-world-example" class="ps-heading wp-block-heading">A Real World Example<a class="ps-heading-anchor" href="#a-real-world-example" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><p>I&rsquo;m going to use a public function Get-SmaAsset for this example. For this particular function, I&rsquo;m wrapping an API call and passing a specific endpoint as a string, determined by the parameter set(s) given. Here is the relevant bit of code:</p><p><code>Begin { $Endpoint = '/api/asset/assets/' If ($AssetID) { $Endpoint = "/api/asset/assets/$AssetID/" If ($AsBarcodes) { $Endpoint = "/api/asset/assets/$AssetID/barcodes" } } }</code>We see</p><p><code>$Endpoint</code>being dynamically defined according to the parameters fed to the parent</p><p><code>Get-SmaAsset</code>function. I needed to ensure that the correct value of</p><p><code>$Endpoint</code>was being fed to the next part of the chain, which was the</p><p><code>Invoke-RestMethod</code>call to the API itself. The last thing I want to debug is why my API call is hitting the wrong endpoint. (Not to mention the potentially disastrous results when HTTP methods other than GET are used!)</p><p>You don&rsquo;t need an intimate knowledge of the project to understand what&rsquo;s going on here - I&rsquo;m really just wanting to make sure that this particular function only uses a single GET method, and that it calls the correct endpoint. An easy way to do this is by leveraging the verbose output stream to ensure that</p><p><code>Get-SmaAsset</code>is in fact, seeking out the correct endpoint with the correct HTTP method.</p><p>Here&rsquo;s part of what the function returns when run verbosely under normal circumstances:</p><p><code>PS&gt; Get-SmaAsset -Server 'https://server.example.com' -Credential (Get-Credential) -Verbose VERBOSE: Performing the operation "GET /api/asset/assets/" on target "https://server.example.com".</code>## Plugging It Into Pester {.wp-block-heading}</p><p>Pester is the perfect tool to test that my API calls go out consistently every time, and to do so I just need to use the Verbose output stream, then mock some response data, and then I should get a pretty clear idea exactly what is going on within my function scope.</p><p>Let&rsquo;s see what the &lsquo;Backend Calls&rsquo; context block looks like for this particular test:</p><p><code>Context 'Backend Calls' { Mock New-ApiGetRequest { } -ModuleName KaceSMA Mock New-ApiPostRequest { } -ModuleName KaceSMA Mock New-ApiPutRequest { } -ModuleName KaceSMA Mock New-ApiDeleteRequest { } -ModuleName KaceSMA $MockCred = New-Object System.Management.Automation.PSCredential ('fooUser', (ConvertTo-SecureString 'bar' -AsPlainText -Force)) $GenericParams = @{ Server = 'https://foo' Credential = $MockCred Org = 'Default' QueryParameters = "?paging=50" } $AssetIDParams = @{ Server = 'https://foo' Credential = $MockCred Org = 'Default' AssetID = '1234' QueryParameters = "?paging=50" } $AsBarcodesParams = @{ Server = 'https://foo' Credential = $MockCred Org = 'Default' AssetID = '1234' AsBarcodes = $True QueryParameters = "?paging=50" } Get-SmaAsset @AssetIDParams It 'should call New-ApiGETRequest' { Assert-MockCalled -CommandName New-ApiGETRequest -ModuleName KaceSMA -Times 1 } It 'should not call additional HTTP request methods' { $Methods = @('POST', 'DELETE', 'PUT') Foreach ($Method in $Methods) { Assert-MockCalled -CommandName ("New-Api$Method" + "Request") -ModuleName KaceSMA -Times 0 } } It "should call generic endpoint if AssetID parameter is NOT specified" { $Generic = $(Get-SmaAsset @GenericParams -Verbose) 4&gt;&amp;1 $Generic | Should -Be 'Performing the operation "GET /api/asset/assets" on target "https://foo".' } It "should call AssetID endpoint if AssetID parameter is specified" { $WithAssetID = $(Get-SmaAsset @AssetIDParams -Verbose) 4&gt;&amp;1 $WithAssetID | Should -Be 'Performing the operation "GET /api/asset/assets/1234" on target "https://foo".' } It "should call AsBarcodes endpoint if AsBarcodes parameter is specified" { $AsBarcodes = $(Get-SmaAsset @AsBarcodesParams -Verbose) 4&gt;&amp;1 $AsBarcodes | Should -Be 'Performing the operation "GET /api/asset/assets/1234/barcodes" on target "https://foo".' } }</code>Now, let&rsquo;s focus on a single test. This is where the &lsquo;cool&rsquo; factor of output streams comes into play. $Generic performs a mocked call to our function, which has a curious bit at the end,</p><p><code>4&gt;&amp;1</code>.</p><p><code>It "should call generic endpoint if AssetID parameter is NOT specified" { $Generic = $(Get-SmaAsset @GenericParams -Verbose) 4&gt;&amp;1 $Generic | Should -Be 'Performing the operation "GET /api/asset/assets" on target "https://foo".' }</code>What this does is take the verbose output stream (</p><p><code>4</code>) and redirect it to stdout (</p><p><code>&gt;&amp;1</code>) for our test to report on. The beauty of this is in it&rsquo;s simplicity. We don&rsquo;t have to modify anything in our code itself since it&rsquo;s an advanced function, and</p><p><code>-Verbose</code>is included by default.</p><p>When we do this we get several key benefits. By explicitly stating the known-good verbose output in our tests, it would begin failing if any of these scenarios occurred in our codebase:</p><ul><li><p>If the endpoint is changed intentionally</p></li><li><p>If the endpoint selection logic is flawed</p></li><li><p>If the HTTP method declared is changed</p></li><li><p>If the HTTP Method is ever used more than once</p></li></ul><p>I hope this has been helpful in exploring how the verbose output stream can help detect stealthy bugs in your codebase.</p>
]]></content:encoded></item><item><title>ICYMI: PowerShell Week of 12-April-2019</title><link>https://powershell.org/articles/2019-04-12-icymi-powershell-week-of-12-april-2019/</link><guid>https://powershell.org/articles/2019-04-12-icymi-powershell-week-of-12-april-2019/</guid><pubDate>Fri, 12 Apr 2019 15:00:00 +0000</pubDate><description>&lt;p&gt;Topics include splatting, PSRemoting to Azure VMs, and honey users.&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>Topics include splatting, PSRemoting to Azure VMs, and honey users.</p><p>Special thanks to Robin Dadswell and Mark Roloff</p><h6 id="moving-my-blog-comments-from-disqus-to-github-issues-using-powershell" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190412.md#moving-my-blog-comments-from-disqus-to-github-issues-using-powershell"/><a href="https://lazywinadmin.com/2019/04/moving_blog_comments.html"><em>Moving my blog comments from Disqus to Github issues using PowerShell</em></a><a class="ps-heading-anchor" href="#moving-my-blog-comments-from-disqus-to-github-issues-using-powershell" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by François-Xavier Cat on April 7th</p><p>More than a few fun goodies in here, from working with XML to using the PS GitHub module.</p><h6 id="powershell-tricks-splatting" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190412.md#powershell-tricks-splatting"/><a href="https://blog.destruktive.one/powershell-tricks-splatting/"><em>PowerShell tricks: Splatting</em></a><a class="ps-heading-anchor" href="#powershell-tricks-splatting" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Roberth Strand on April 5th</p><p>If you&rsquo;re not already splatting, take a look in here. All the cool kids are doing it and anyone that has to read your scripts later on will likely thank you. It&rsquo;s a very simple, yet seriously versatile addition to your toolbox.</p><h6 id="powershell-basics-connecting-to-vms-with-azure-psremoting" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190412.md#powershell-basics-connecting-to-vms-with-azure-psremoting"/><a href="https://techcommunity.microsoft.com/t5/ITOps-Talk-Blog/PowerShell-Basics-Connecting-to-VMs-with-Azure-PSRemoting/ba-p/428403"><em>PowerShell Basics: Connecting to VMs with Azure PSRemoting</em></a><a class="ps-heading-anchor" href="#powershell-basics-connecting-to-vms-with-azure-psremoting" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Michael Bender on April 10th</p><p>Whether from the comfort of your local shell or the Cloud Shell, remote PowerShell to your Azure VMs is quick and easy to get started with.</p><h6 id="bluehive" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190412.md#bluehive"/><a href="https://github.com/leeberg/BlueHive"><em>BlueHive</em></a><a class="ps-heading-anchor" href="#bluehive" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>Built with Universal Dashboard, BlueHive is a utility that lets you create and manage honey users in your environment. Thanks for this awesome tool, Lee Berg!</p><h6 id="reddit-rpowershell---popular-weekly-post" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190412.md#reddit-rpowershell---popular-weekly-post"/><a href="https://old.reddit.com/r/PowerShell/comments/bbz6vj/i_got_a_job_for_my_ability_with_powershell_and_im/"><em>Reddit /r/PowerShell - Popular Weekly Post</em></a><a class="ps-heading-anchor" href="#reddit-rpowershell---popular-weekly-post" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>Less educational or interesting, and more encouraging. If you&rsquo;re on the fence with jumping deeper into PowerShell, here&rsquo;s someone sharing their story of how it helped kick their career up a few notches.</p><h6 id="tweet-of-the-week" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190412.md#tweet-of-the-week"/><a href="https://twitter.com/DanielSilv9/status/1116375543581216770"><em>Tweet of the Week</em></a><a class="ps-heading-anchor" href="#tweet-of-the-week" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>Playing with</p><p><code>Invoke-WebRequest</code>is a little bit more fun with Chrome&rsquo;s DevTools letting you copy requests to your clipboard.</p>]]></content:encoded></item><item><title>Hear, Hear for Here-Strings</title><link>https://powershell.org/articles/2019-04-09-hear-hear-for-here-strings/</link><guid>https://powershell.org/articles/2019-04-09-hear-hear-for-here-strings/</guid><pubDate>Tue, 09 Apr 2019 01:40:55 +0000</pubDate><description>&lt;p&gt;Running commands in PowerShell that require a format that will not run natively in PowerShell could be a difficult task, or can it? PowerShell provides a way to store, for example, a JSON as a string, enter here-string. A here-string is a single or double quoted string in which the quotation marks are interpreted literally. An example would be invoking a Rest API that requires a JSON body. Lets take a look at an example and see how here-strings work.&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>Running commands in PowerShell that require a format that will not run natively in PowerShell could be a difficult task, or can it? PowerShell provides a way to store, for example, a JSON as a string, enter here-string. A here-string is a single or double quoted string in which the quotation marks are interpreted literally. An example would be invoking a Rest API that requires a JSON body. Lets take a look at an example and see how here-strings work.</p><p>Trying to store JSON in a variable will return the following error:</p><p>`$Body =
{
&ldquo;apple&rdquo;: [
&ldquo;red&rdquo;,
&ldquo;green&rdquo;
],
&ldquo;grape&rdquo;: [
&ldquo;green&rdquo;,
&ldquo;red&rdquo;
],
&ldquo;blueberry&rdquo;: &ldquo;blue&rdquo;
}
At line:3 char:12</p><ul><li><pre><code>"apple": [</code></pre></li><li><pre><code> ~</code></pre></li></ul><p>Unexpected token &lsquo;:&rsquo; in expression or statement.
At line:6 char:6</p><ul><li><pre><code>],</code></pre></li><li><pre><code> ~</code></pre></li></ul><p>Missing argument in parameter list.
At line:10 char:6</p><ul><li><pre><code>],</code></pre></li><li><pre><code> ~</code></pre></li></ul><p>Missing argument in parameter list.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
`Oh man&hellip; What happened? PowerShell does not understand what is being done and throws an error for an unexpected token. Lets declare this as a here-string by using</p><p><code>@'</code>at the start and end of the JSON variable.</p><p><code>$Body = @' { "apple": [ "red", "green" ], "grape": [ "green", "red" ], "blueberry": "blue" } '@</code>Great! No errors were thrown, but… Why?</p><p>Notice the</p><p><code>@'</code>at the beginning and end, this tells PowerShell to create a here-string and store this string in a variable. Also, a rule to follow: the</p><p><code>@'</code>must be on their own line at the start and end of the declaration or the here-string will not be declared.</p><p><code># This will not work, PowerShell will not throw an error, but thinks you are still working to create something. $Body = @'{ "apple": [ "red", "green" ], "grape": [ "green", "red" ], "blueberry": "blue" } '@</code>We can also store variables in a here-string, but that requires double quotes after the</p><p><code>@</code>. The same rules apply as using single quoted here-strings.</p><p><code>$Red = 'red' $Green = 'green' $Blue = 'blue' $Body = @" { "apple": [ $Red, $Green ], "grape": [ $Green, $Red ], "blueberry": $Blue } "@</code>Now that we built our here-string, we can now invoke a Rest API and do something with it. This will help when a vendor supplies a JSON payload to be used in a Rest API, all that needs to be done is substitute your values in a here-string and invoke the Rest API. As always, practice makes perfect, try running examples in the console before running in a production environment. Here-strings will save you some lines of code and time when building your PowerShell scripts.</p><p>To learn about here-strings, visit Microsoft&rsquo;s documentation on quoting rules.<br><a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-6">https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-6</a></p><p>Chris Liquori - Twitter:<a href="https://twitter.com/pwshliquori">@pwshliquori</a></p>
]]></content:encoded></item><item><title>ICYMI: PowerShell Week of 5-April-2019</title><link>https://powershell.org/articles/2019-04-05-icymi-powershell-week-of-5-april-2019/</link><guid>https://powershell.org/articles/2019-04-05-icymi-powershell-week-of-5-april-2019/</guid><pubDate>Fri, 05 Apr 2019 15:00:51 +0000</pubDate><description>&lt;p&gt;Topics include remoting with SSH, sending SMS alerts, some live stream coding, and keybinds that you may not have known about.&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>Topics include remoting with SSH, sending SMS alerts, some live stream coding, and keybinds that you may not have known about.</p><p>Content curated by Robin Dadswell and Mark Roloff</p><h6 id="master-user-creator-" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190405.md#master-user-creator-powershell-gui-software-v2-update"/><a href="https://www.thelazyadministrator.com/2019/04/01/master-user-creator-powershell-gui-software-v2-update/"><em>Master User Creator [PowerShell GUI Software] v2 Update</em></a><a class="ps-heading-anchor" href="#master-user-creator-" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Brad Wyatt on April 1st</p><p>MUC, if you haven&rsquo;t seen it, is a powerful little tool that makes account creation in AD or O365 a real snap.</p><h6 id="the-powershell-gallery-is-now-more-accessible" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190405.md#the-powershell-gallery-is-now-more-accessible"/><a href="https://devblogs.microsoft.com/powershell/the-powershell-gallery-is-now-more-accessible/"><em>The PowerShell Gallery is now more Accessible</em></a><a class="ps-heading-anchor" href="#the-powershell-gallery-is-now-more-accessible" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Sydney Smith on April 1st</p><p>Screen readers rejoice! The Gallery has received some usability improvements to make everyone&rsquo;s experience a little nicer.</p><h6 id="sending-text-messages-from-powershell" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190405.md#sending-text-messages-from-powershell"/><a href="https://mtreit.net/notestoself/2019/03/30/sending-text-messages-from-powershell/"><em>Sending text messages from PowerShell</em></a><a class="ps-heading-anchor" href="#sending-text-messages-from-powershell" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Mike Treit on March 30th</p><p>Maybe you get enough emails as it is, so text alerts from your scripts can be a gentler and lighter alternative.</p><h6 id="setup-powershell-ssh-remoting-in-powershell-6" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190405.md#setup-powershell-ssh-remoting-in-powershell-6"/><a href="https://www.thomasmaurer.ch/2019/04/setup-powershell-ssh-remoting-in-powershell-6/"><em>Setup Powershell SSH Remoting In Powershell 6</em></a><a class="ps-heading-anchor" href="#setup-powershell-ssh-remoting-in-powershell-6" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>by Thomas Maurer on April 4th</p><p>If you&rsquo;ve been curious about using SSH with PowerShell, Thomas has a great step-by-step guide to help you get going.</p><h6 id="reddit-rpowershell---popular-weekly-post" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190405.md#reddit-rpowershell---popular-weekly-post"/><a href="https://old.reddit.com/r/PowerShell/comments/b8y4mx/i_was_today_years_old/"><em>Reddit /r/PowerShell - Popular Weekly Post</em></a><a class="ps-heading-anchor" href="#reddit-rpowershell---popular-weekly-post" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>Awesome Reddit tips strikes again, as /u/RC-7201 discovers a keybind to clear your screen and more people chime in with their hidden keybind gems.</p><h6 id="tweet-of-the-week" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190405.md#tweet-of-the-week"/><a href="https://twitter.com/TylerLeonhardt/status/1113078631771799553"><em>Tweet of the Week</em></a><a class="ps-heading-anchor" href="#tweet-of-the-week" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>A Docker container loaded up with everything you need to get crackin&rsquo; with PowerShell development? Yes, please!</p><h6 id="twitch-powershell-adventures-w-nate--scrt-hq" class="ps-heading wp-block-heading"><a href="https://github.com/devops-collective-inc/WhatYouMissedThisWeek/blob/master/20190405.md#twitch-powershell-adventures-w-nate--scrt-hq"/><a href="https://www.twitch.tv/videos/403373735"><em>Twitch: PowerShell Adventures w/ Nate @ SCRT HQ</em></a><a class="ps-heading-anchor" href="#twitch-powershell-adventures-w-nate--scrt-hq" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h6><p>Hang out with Nate Ferrel while he works through some open issues with the PSGSuite module.</p>]]></content:encoded></item></channel></rss>