Archive

Posts Tagged ‘PowerShell’

Function: Get-UpdateInfo – Making It Easy for Your Users to Get the Latest Version of Your Scripts

October 10th, 2016 No comments

updatepromptDescription

As a PowerShell developer, you always want your users to have the latest version of a script. It makes support a lot easier, while also making sure that users have the latest features and bug fixes. But how to encourage that? Well, for me, users of my scripts are typically not within the same environment as me. So Group Policy Objects, logon scripts, etc, aren’t a solution. Having the script automatically check for an update is much easier, and doesn’t require anything from the user1. So let’s take a look at a quick and easy method.

First, we need a repository where the update information will be held. XML is perfect for this. In this example, I created the following file, and saved it as version.xml:

<?xml version="1.0"?>
<catalog>
<article id="1697">
<title>Set-CsFeatures.ps1</title>
<author>Pat Richard</author>
<version>3.9.57</version>
<publish_date>2016-10-08</publish_date>
<description>Installs all required Windows 2012/Windows 2012 R2 components & optional tools.</description>
</article>
</catalog>

This file can reside anywhere. A file path, a web site, wherever. I chose a website for the reasons I mentioned above. You can see the above file in action at https://www.ucunleashed.com/downloads/version.xml. Some key points to the file. Each article I publish going forward will have it’s own “article” node. The ID I chose to tie to it is also the ID of the article’s URL, for consistency sake. In this example, 1697 is the prereq script seen at https://www.ucunleashed.com/1697. The version value is the version of the latest general availability (“GA”) build. We’ll query that value, compare it against the version of the script running the query, and see if it’s newer. Note that there is some other info in the XML file, and that’s irrelevant to what we’re discussing here.

[xml] $xml = (New-Object System.Net.WebClient).DownloadString("https://www.ucunleashed.com/downloads/version.xml")
$Ga = ($xml.catalog.article | Where-Object {$_.id -eq $article}).version

We supply the $article value when making the call. After that, it’s a simple comparison. In the prereq script, near the beginning, I assign a variable, $version, with a value. Let’s say it’s “3.9.55”. We compare $Ga against $Version

$Ga -gt $Version

If it’s true, we know a newer version exists. If it’s false, we know the currently running script is the latest version. In theory, we could also use this to alert of a regression in case we needed to downgrade (gasp!). So let’s put this together. We assign a variable, $xml, to the results of downloading an xml file. Then, we assign $ga to the value of “version” for the specific node within the xml file that contains the info for the article. Lastly, we do our comparison and give some output if there is an update.

[xml] $xml = (New-Object System.Net.WebClient).DownloadString("https://www.ucunleashed.com/downloads/version.xml")
$Ga = ($xml.catalog.article | Where-Object {$_.id -eq $article}).version
if ($Ga -gt $Version){Write-Output "A new version is available!"}

Now, obviously, we can pretty this up a bit. But before we do that, let’s think of issues we could run into. The big one is making sure we have an Internet connection to use to check the XML file. As much as we can often assume there will be one, a LOT of organizations block Internet access to servers as part of their security posture. So we shouldn’t assume. We can check using the following:

[bool] $HasInternetAccess = ([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')).IsConnectedToInternet)

And then using an IF loop against $HasInternetAccess. So let’s throw this all into a function we can incorporate into our scripts and modules:

function Get-UpdateInfo {
  [CmdletBinding(SupportsShouldProcess, SupportsPaging)]
  param (
    # Article/script to check for updates
    [parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)]
    [string] $article
  )
  [bool] $HasInternetAccess = ([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')).IsConnectedToInternet)
  if ($HasInternetAccess){
    [xml] $xml = (New-Object System.Net.WebClient).DownloadString("https://www.ucunleashed.com/downloads/version.xml")
    $Ga = ($xml.catalog.article | Where-Object {$_.id -eq $article}).Version    
    if ($Ga -gt $version){
      Write-Log -Level Warn -Message "Outdated version. Version $Ga is latest version. Prompting user" -NoConsole
      $wshell = New-Object -ComObject Wscript.Shell -ErrorAction Stop
      $updatePrompt = $wshell.Popup("A new version ($ga) of the script is available. Would you like to download it?",0,"A new version is available",68)
      if ($updatePrompt -eq 6){
        Start-Process "https://www.ucunleashed.com/$article"
      }
    }
  }else{
    Write-Output "No Internet connectivity. Unable to check online for update info."
  }
} # end function function Get-UpdateInfo

Here we incorporate a simple ComObject popup message to ask if the user wants to download the new version. Since we have assigned the GA number to $ga, we can use that in the popup text, as well, as shown in the image at the beginning of this article. If $updatePrompt is “6”, then the user clicked “Yes” on the popup, and we can take action such as opening a browser window and navigating to the articles page. Or we could download a file, or any of a number of actions. If $updatePrompt is “7”, then the user clicked “No”.

So, as you can see, it’s really not that hard to add an update checker to your scripts. When you release a new version, simply update the XML file to reflect accordingly.

Note: Take care in what kind of characters are in the XML file. Some special characters, such an ampersand (“&”), aren’t handled very well. When in doubt, open a browser window and navigate to the file.

1 – Depending on the action you require once it’s known an update is available.

Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

One Liner: Enabling Mapped Drives in Elevated PowerShell Sessions

July 18th, 2016 No comments

If you’ve worked with mapped drives in PowerShell sessions, you know it’s problematic to access mapped drives from an elevated PowerShell session when UAC is configured to prompt to prompt for credentials. Microsoft released a TechNet KB article on this issue quite some time ago. The article shows different ways to address the problem, from using the Local Security Policy, mapping the drives again in the elevated prompt, and using the registry. We’ll focus on the registry here for several reasons. The first is that using the local security policy seems burdensome; mapping the drives again seems redundant, and potentially confusing if the original mappings change and the ones in your PowerShell session don’t; and thirdly, and most important, we’re talking PowerShell here!

The local security policy really just changes registry settings under HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System, so using PowerShell to set registry settings accomplishes the same thing. We can add new property, EnableLinkedConnections using the New-ItemProperty cmdlet, which also lets us set its value to 1. A value of 1 will enable the mapped drives in elevated session, while a value of 0, or completely removing the property, disables those mapped drives in an elevated session. So let’s implement this:

New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' -Name EnableLinkedConnections -Value 1 -PropertyType 'DWord'

Now, if you want to put this in your PowerShell profile, then it will get processed every time. The problem is that you’ll get a “The property already exists” exception error every time it runs after the first time. So, we just wrap it in an IF statement using Get-ItemProperty, checking to see if it exists first. If not, create the item property.

if (-not (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' -Name EnableLinkedConnections)){
  $null = New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' -Name EnableLinkedConnections -Value 1 -PropertyType 'DWord'
}

Why would we want to include this in our profile? Because when we get new machines, or reload an existing machine, we don’t want to have to go back and manually configure everything again. We can just manually run the profile script and have it configure everything for us.

Categories: PowerShell Tags: , ,

One liner: Find Lync/Skype for Business Users Whose Extension Doesn’t Match Part of Their DID

September 18th, 2015 2 comments

Description

 

Get-CsUser -Filter {LineURI -ne $null} | Where-Object {$_.LineURI.Split("=")[1] -NotMatch $_.LineURI.Substring($_.LineURI.Split(";")[0].Length -4,4)} | Select-Object DisplayName,LineURI | Sort-Object DisplayName

One Liner – See Number Of Connected Users, Endpoints On A Lync Front End Server

January 22nd, 2015 5 comments

A question went around an internal DL at work today asking if anyone knew off the top of their head the name of performance counters that show connected users and endpoints. While digging up the answer, I started thinking – this would be a great little one liner.

My esteemed colleague Ron Cook (@roncook925) beat me to supplying the answer to the DL question. The two counters are:

LS:USrv – Endpoint Cache\USrv – Active Registered Endpoints
LS:USrv – Endpoint Cache\USrv – Active Registered Users

Endpoints is always higher than users, in my experience. There are always some users who are connected via mobile devices and rich client, or via OWA, or LPE. So I like to query both.

PowerShell has a great cmdlet called Get-Counter which, as you can guess, can query performance counters. There’s a pretty good tutorial on how to retrieve perfmon counter data for Lync related counters by the Lync PowerShell group at Microsoft in How Do We Love Performance Counters” Let Us Count the Ways. So let’s take a look at how we can get the data we need.

In this case, we’ll query the two counters mentioned above with one line. This is supported in Get-Counter by just separating the counters with a comma. We’ll select an expanded property called CounterSamples, which holds the data we need (among other info). And lastly, we’ll output the path (counter name), and something called the CookedValue, which is the actual counter value contained within CounterSamples. I know, CookedValue sounds like it could be just made up numbers, like those you get from a shifty accountant. But it is truly the value we want.

Plug this into your console as one long line:

Get-Counter "\LS:USrv - Endpoint Cache\USrv - Active Registered Endpoints","\LS:USrv - Endpoint Cache\USrv - Active Registered Users" | Select-Object -ExpandProperty CounterSamples | Format-Table Path,CookedValue -Auto

That will give you a quick point-in-time snapshot of the number of users and endpoints connected to the front end, as shown below.

perfmon

The blurred text is just the front end name. If you’d like to query a remote front end, just tack on the ComputerName parameter, such as:

Get-Counter "\LS:USrv - Endpoint Cache\USrv - Active Registered Endpoints","\LS:USrv - Endpoint Cache\USrv - Active Registered Users" -ComputerName frontend.contoso.com | Select-Object -ExpandProperty CounterSamples | Format-Table Path,CookedValue -Auto

For those wondering why I’m using Format-Table and the -Auto parameter, it’s because the counter path value is so long that it would otherwise get truncated short enough to where you wouldn’t know which counter was tied to which value.

Changelog: New-SignedScript

June 10th, 2014 No comments

This is the changelog page for New-SignedScript. You will find a complete list of released versions, their dates, and the features and issues addressed in each. Please refer to the script’s main page for more information including download links, installation details, and more.

v1.3 – 09-18-2016

  1. Now includes a selection box when more than one valid code signing certificate is found.

v1.1 – 06-10-2014

  1. Better handling when there is more than one code signing cert. Script now finds the first valid code signing cert and uses that.
  2. Better validation that the script is successfully signed

v1.0 – 09-20-2012

  1. Initial version
Categories: PowerShell Tags: , ,

Script: Get-CsFederatedConversationDetails.ps1 – See Stats About Conversations With Specific Federated Domains

May 13th, 2014 5 comments

Lync 2013 logo 128x128Description

Richard Schwendiman, PFE at Microsoft, came up with a great SQL query that you could plug into SQL Server Management Studio to see time & date info for conversations with federated or PIC domains. In Richard’s case, he used the aol.com PIC domain. Since PIC federation with AOL and Yahoo is ending next month, I thought this was great timing on Richard’s part. But sometimes, Lync admins can’t login to SQL servers to run queries due to security policy. Plus, the query is something you’d have to keep handy and edit accordingly each time you wanted to get data. So I figured – hey, why not whip up a quick script to allow an admin to query SQL for this data, allowing for any domain and time frame to be specified? Poof – out comes my script.

This script will query a specific SQL server for information about a specific federated SIP domain. The domain does NOT need to be in the allowed domains list if you’re open federating. Any SIP domain name works. You can specify a start date/time in the yyyy-MM-dd format, such as 2014-05-13 using the -TimeSpan parameter. Or, you can use some handy ranges I’ve included, including LastWeek (the last 7 days), Last30Days, Last year (last 365 days), FirstOfYear or ThisYear (since Jan. 1), FirstOfMonth or ThisMonth (since the 1st of the month), FirstOfWeek or ThisWeek (since Sunday). Optionally, you can specify an end date/time in the yyyy-MM-dd format. This script will default to FirstOfYear with no end date, and aol.com for the domain. As we see below, only the SQL server holding the LcsCDR database is queried.

aol3

Now, from this output, we see that there is not a lot of communications with people on AOL since the first of the year. The upcoming change should have very little impact.

If you’re using a named instance in SQL, you can specify it as well.

The script outputs a full object, just like other cmdlets, so you can pipe it to other commands to alter the display, including sorting, or my favorite, Out-GridView, as well as outputting to files such as .csv.

Hopefully, this tool will make life a little easier in digging out data.

Syntax

Get-CsFederatedConversationDetails.ps1 [[-SqlServer] ] [[-SqlInstance] ] [[-SipDomain] ] [[-TimeSpan] <object>] [[-EndDate] <object>] [-WhatIf ] [-Confirm ] [<commonparameters>]</commonparameters></object>

Installation

Execution Policy: Third-party PowerShell scripts may require that the PowerShell Execution Policy be set to either AllSigned, RemoteSigned, or Unrestricted. The default is Restricted, which prevents scripts – even code signed scripts – from running. For more information about setting your Execution Policy, see Using the Set-ExecutionPolicy Cmdlet.

Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

Assumptions

None

Download

v1.0 – 05-13-2014 – Get-CsFederatedConversationDetails.v1.0.zip

Changelog

See the changelog for information on what’s changed/included in each version.

 

Changelog: Get-CsFederatedConversationDetails.ps1

May 13th, 2014 No comments

This is the changelog page for Get-CsFederatedConversationDetails.ps1. You will find a complete list of released versions, their dates, and the features and issues addressed in each. Please refer to the script’s main page for more information including download links, installation details, and more.

v1.0 – 05-13-2014

  1. Initial version

New Syntax Highlighting and Auto-Complete Files for UltraEdit includes PowerShell v4, AD, Lync 2013, and Exchange 2013

March 12th, 2014 No comments

Syntax highlighting

Updated the wordfile a little bit. This one includes all previous functions as well as the following:

  1. PowerShell v4 cmdlets (the ones available when you open a new v4 session).
  2. Exchange 2013 SP1 cmdlets
  3. Lync 2013 cmdlets
  4. Active Directory cmdlets

That adds up to 2834 cmdlets/functions that get syntax highlighting on top of the 137 aliases that are also in the file. The file also has variable highlighting, as well as operators and comp operators highlighting.

Formatting changes include the following:

  1. code folding for (), so your long param() blocks can now be collapsed/expanded.
  2. code folding for region/endregion. This mimics the behavior of ISE.

If you’d like to change the colors and/or fonts used for highlighting, go to View>Themes>Manage Themes, or Layout>Themes>Manage Themes (depending on your version of UltraEdit) as the styling in the wordfile is ignored starting with v20 of UltraEdit.

manage themes

As with all other wordfiles, they are stored in “%appdata%\IDMComp\UltraEdit\Wordfiles\”, unless you change the path in Advanced>Configuration>Editor Display>Syntax Highlighting or Advanced>Settings>Editor Display>Syntax Highlighting (again, depending on your installed version of UltraEdit).

wordfile path

You can optionally set the “Highlight new file as:” to PowerShell, as I do (also shown above).

As soon as you place this wordfile in that folder, you should see PowerShell as an option under View>View as (Highlighting File Type)

view as highlighting

Auto-complete

I’ve also created an auto complete file that contains the same cmdlet/function names as the syntax highlighting file. When enabled, you get tab completion of cmdlet and function names similar to the PowerShell console and ISE. Note, however, that in UltraEdit, you only get auto-complete of the cmdlet/function names, not their parameters.

You can save the file anywhere. Then, go to Advanced>Configuration>Editor>Word Wrap/Tab Settings (or Advanced>Settings>Editor>Word Wrap/Tab Settings) to specify the location within UltraEdit:

auto-complete path

Then go to Auto-complete and check the box “Show auto-complete dialog automatically” and also enter a number in the box. 5 works for me.

auto-complete options

Now, when typing a cmdlet/function that’s in the auto-complete file, you’ll get suggestions.

auto-complete suggestions

Up/down errors navigate through the list, and tab uses the highlighted suggestion.

Download

UltraEditSyntaxHighlighingAuto-CompleteFiles.zip

Function: Set-PowerPlan – Adjust The Power Plan of a Server

February 25th, 2014 2 comments

Description

Just something I worked up based on a suggestion by someone. This will change the power plan of the machine it’s run on. This can be critical if you want to ensure that the machine doesn’t go to sleep while an extended process is running. Simply run the function with the desired power plan and the change is immediate. For example:

Set-PowerPlan "High Performance"

The three power plans you can choose from are “high performance”, “balanced”, and Power Saver. That’s all there is to it.

function Set-PowerPlan {
	[CmdletBinding(SupportsShouldProcess = $True)]
	param (
		[ValidateSet("High performance", "Balanced", "Power saver")]
		[ValidateNotNullOrEmpty()]
		[string] $PreferredPlan = "High Performance"
	)
	 
	Write-Verbose "Setting power plan to `"$PreferredPlan`""
	$guid = (Get-WmiObject -Class Win32_PowerPlan -Namespace root\cimv2\power -Filter "ElementName='$PreferredPlan'").InstanceID.ToString()
	$regex = [regex]"{(.*?)}$"
	$plan = $regex.Match($guid).groups[1].value 
	
	powercfg -S $plan
	$Output = "Power plan set to "
	$Output += "`"" + ((Get-WmiObject -Class Win32_PowerPlan -Namespace root\cimv2\power -Filter "IsActive='$True'").ElementName) + "`""
	Write-Verbose $Output
}

Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

Categories: PowerShell Tags: ,

Resetting the Font in Lync Server Control Panel – Goodbye Times New Roman!

January 20th, 2014 1 comment

Many people have noticed that after installing the Lync Server 2013 Cumulative Update from October, 2013, that the font in the Lync Server Control Panel changed to Times New Roman from the original Segoe UI font.

LSCP font2

Lots of people commented online that they were not fans of the change (myself included), and wanted it changed back. The issue was raised with Microsoft who verified that there was no change in the font requested when displaying the Control Panel. This was confirmed by looking through the logs. The problem was an Internet Explorer compatibility issue. Servers that have IE 8 don’t exhibit the problem, but those with IE 9 or later, do. Instead of looking at the font defined by MS Shell Dlg registry value (HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitues\MS Shell Dlg), the Control Panel was using the font configured in IE. If you look in Internet Options>Fonts, you see that the Webpage font is set to Times New Roman.

LSCP font

We can get the original Segoe UI font back by simply changing the webpage font option to Segoe UI, closing the Control Panel, and opening it back up. We can also make the change using PowerShell by changing the value of the registry key that gets set when you use the above method. To do so, open PowerShell, and enter the following:

Set-ItemProperty -path "HKCU:\Software\Microsoft\Internet Explorer\International\Scripts\3" -Name IEPropFontName -Value "Segoe UI"

And after restarting the Control Panel, we see it’s back to the way it should be.
LSCP font3

You can set the value to any font, really, including Comic Sans MS, as requested by my buddy Ken “The Hoff” Lasko.

Something to keep in mind is that changing that value does have the potential for changing the way other web pages look as well, as this is more of a work-around than a fix. But I’ve not run into that, yet. I’ll post more info as I get it.