Archive

Archive for the ‘PowerShell’ Category

Script: New-ExpiringCertificatesReminder.ps1 – Receive a Reminder When Certificates Have Expired/Are Expiring

September 14th, 2012 2 comments

Detailed Description

Sometimes we’re so deep in projects or putting out fires that some things just get forgotten, or we don’t get that far down the “to-do” list. Some of those things aren’t that big of a deal and don’t impact users. Other tasks can have drastic impact. Such as forgetting to renew your server certificates. It’s true that some services like the phenomenal DigiCert will remind-you-to-death about certs that are expiring. But not all services do that, or they do it once and are forgotten. Other certs, like internal certs, don’t generate a reminder – and some environments don’t allow, or aren’t configured to automatically renew internal certificates. So this lazy, forgetful guy decided to do something about that. A script was born.

This script monitors certificates in the Local Machine store on the local server, and sends a reminder when a cert is expiring soon, or has already expired. An example is shown below.

Sample email about an expired certificate

Sample email about an expired certificate

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.

Download the script and ImageFiles.zip files from the DOWNLOAD section below. Copy the image files to a location available to all users who will receive the reminder email. I suggest a web server with public access. NOTE: These images are the SAME files and names as the ones for New-PasswordReminder.ps1, so you can use the same path if you use both scripts.

Open the script in a text editor and edit the variables in the param block to suit your needs. At a bare minimum, you need to adjust:

  • $Company – this should be your company name
  • $PSEmailServer – this is the email server the script will send the emails to
  • $EmailFrom – this is the SMTP address that the emails will come FROM
  • $EmailTo – set this to the SMTP address of the user/distribution group that should receive the reminder emails
  • $HelpDeskPhone – if not empty, this appears in the email message
  • $HelpDeskURL – if not empty, should be a URL to a web version of the email. If blank, the “If this email does not appear…” and “This email was sent by…” lines shown in the above example are not included.
  • $ImagePath – where the images are stored. This should be publicly reachable for users checking email from mobile devices and web clients

optionally, adjust $threshold from the default 15 to indicate how many days in advance the script should start reminding about an expiring certificate.

Save the script.

If you don’t already have a Receive Connector in Exchange to allow PowerShell scripts to send email, create one using the information at Creating A Receive Connector To Use For Sending Email From PowerShell.

If you have certs that are already expired, or are expiring soon, you can manually run the script to test. To do that, open PowerShell and type

New-ExpiringCertificatesReminder.ps1

Once everything is done, you can run the script in Install mode:

New-ExpiringCertificatesReminder.ps1 -Install

and the script will prompt for the user password, then automatically create a scheduled task on the local server to run every day at 7:30am. You can open the Scheduled Tasks GUI and adjust parameters as needed, but I’ve found the defaults to be fine.

Repeat on any other servers you’d like to monitor.

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.

Download

v1.3 – 02-13-2017 – New-ExpiringCertificatesReminder.v1.3.zip

v1.2 – 01-27-2014 – New-ExpiringCertificatesReminder.v1.2.zip

v1.0 – 09-14-2012 - New-ExpiringCertificatesReminder.v1.0.zip

ScriptImages.zip – these are the images specified in the emails

Changelog

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

Categories: PowerShell Tags: ,

Function: New-FirewallRule – Add Windows Firewall Rules Via PowerShell

September 14th, 2012 1 comment

Description

Some of my scripts, namely Get-CsConnections.ps1, require specific firewall rules be created in order to operate correctly. So I set out to automate as much as possible the creation of these rules. A function was born.

This little function can do pretty much everything the Windows Firewall wizard can do. You can specify local and remote ports, local and remote IP addresses, programs, services, direction Inbound or Outbound), TCP/UDP or Any, and more. I borrowed some of the info from the Windows Firewall chm file for the comment-based help file in the function. Just run

Get-Help New-FirewallRule

for detailed help.

I tried to think of (and test) common requirements for firewall rules, but if I’ve left something out, or something isn’t working as expected, feel free to leave a comment below.

Syntax

New-FirewallRule [[-name] ] [[-localPorts] ] [[-remotePorts] ] [[-localAddresses] ]
 [[-remoteAddresses] ] [[-program] ] [[-serviceName] ] [[-description] ] [-outbound] 
[-udp] [-block] [-readonly] [-any] [-domain] [-public] [-private] [-WhatIf] [-Confirm] []

Name This is the name of the firewall rule. As a best practice, give the firewall rule a unique name. If two rules have the same name, then you cannot easily manage them by using the netsh or PowerShell commands. Do not use the name “all” for a firewall rule because that is the name of a netsh command-line tool keyword.

LocalPorts If you are using the TCP or UDP protocol type, you can specify the local port by using one of the choices from the drop-down list or by specifying a port or a list of ports. The local port is the port on the computer on which the firewall profile is applied.

RemotePorts If you are using the TCP or UDP protocol type, you can specify the local port and remote port by using one of the choices from the drop-down list or by specifying a port or a list of ports. The remote port is the port on the computer that is attempting to communicate with the computer on which the firewall profile is applied.

LocalAddresses The local IP address is used by the local computer to determine if the rule applies. The rule applies only to network traffic that goes through a network adapter that is configured to use one of the specified local IP addresses.

RemoteAddresses Specify the remote IP addresses to which the rule applies. Network traffic matches the rule if the destination IP address is one of the addresses in the list.

Program Use this option to match network packets going to or from a specified program. If the program is not running, then no packets match the rule. Type the complete path to the program. You can include environment variables, where appropriate. When you add a program to the rule, Windows Firewall with Advanced Security dynamically opens (unblocks) and closes (blocks) the ports required by the program. When the program is running and listening for incoming traffic, Windows Firewall with Advanced Security opens the required ports; when the program is not running or is not listening for incoming traffic, Windows Firewall with Advanced Security closes the ports. Because of this dynamic behavior, adding programs to a rule is the recommended method for allowing unsolicited incoming traffic through Windows Firewall.

ServiceName Use this option to apply the rule only to services, not to other processes. Specify the short name of the service to which you want the rule to be applied.

Description This is a description of the rule. Use this to provide information about the rule, such as the rule owner, the rule requester, the purpose of the rule, a version number, or the date of creation.

Outbound Configures the rule as outbound. If not specified, the rule is created as inbound.

UDP Use this option to specify that the rule should filter UDP traffic. If not specified, and -Any is also not specified, the rule will filter TCP traffic. Cannot be used with -ANY.

Block Use this option to explicitly block any network packet that matches the firewall rule criteria. The block action takes precedence over the allow action, unless the Override block rules option is selected when the firewall rule is created.

ReadOnly If used, the rule will be created and attributes such as Program, Protocols, and Ports cannot be edited after creation. To change these settings, delete the rule and recreate it.

Any Use the option to filter traffic from any protocol. Cannot be used with -UDP.

Domain Applies when a computer is connected to a network that contains an Active Directory domain controller in which the computer’s domain account resides.

Private Applies when a computer is connected to a network in which the computer’s domain account does not reside, such as a home network. The private profile settings should be more restrictive than the domain profile settings. A network is assigned the private type by a local administrator.

Public Applies when a computer is connected to a domain through a public network, such as one available in airports and coffee shops. The public profile settings should be the most restrictive because the computer is connected to a public network where the security cannot be as tightly controlled as it is in an IT environment. By default, newly discovered networks are assigned the public type.

Examples

There is a vast number of combinations that can be used to create rules. I’ve tested a bunch, but cannot possibly test every conceivable combination. Here are a couple of examples:

New-FirewallRule -Name "Test Rule" -Description "My cool Lync rule" -Domain -Public -Private -Any -Program "C:\Program Files\Microsoft Lync Server 2010\File Transfer Agent\FileTransferAgent.exe" -ReadOnly
New-FirewallRule -name "World Wide Web Services" -description "An inbound rule to allow HTTPS traffic for Internet Information Services (IIS) [TCP 443]" -domain -private -public -localports "443" -Program "System"

Installation

No installation needed. But the function does need to run in an elevated session.

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.

Download

v1.0 (09-14-2012) New-FirewallRule.v1.0.zip

Changelog

See the changelog for information on features and bugs fixed in various versions.

Categories: PowerShell Tags:

Changelog: New-FirewallRule

September 14th, 2012 No comments

This is the changelog page for New-FirewallRule. 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 – 09-14-2012

  1. Initial version
Categories: PowerShell Tags: ,

Function: Remove-NicGateway – Removing the Default Gateway on Selected NICs Via PowerShell

March 13th, 2012 No comments

Description

When deploying Database Availability Groups (DAGs) with Exchange 2010, multiple network are generally used. You’ll have a client or “MAPI” network and at least a replication network. I’ve seen some organizations that also deploy backup networks. Each has their own NICs or NIC teams. Only the client network should have a default gateway defined. The rest should not. Static routes are added for the others using the NETSH command.

Setting the NIC properties is sometimes  a manual task, and sometimes a scripted task via PowerShell. On a large project, I needed to run a validation script to ensure that the servers were consistent and ready for the Exchange build, and fix those that could be done via script. I noticed that servers were coming with gateways defined on all of the NIC teams, so I need to resolve this. Turns out, it was a little challenging to do it via PowerShell.

There is apparently no easy way to just remove the gateway. We can easily set it, but my assumption that setting it to $null would work was incorrect. What I ended up doing, with the assistance of Serkan Varoglu, was to change the NIC from static to DHCP, then back to static, defining only the IP address and subnet mask. Not the most direct method, but it works. And, it appears to leave other parameters intact, including DNS servers, suffixes, WINS, etc.

First we use WMI to grab the NIC by name ($NicName):

$Adapter = Get-WmiObject -Class Win32_NetworkAdapter -Filter "NetConnectionID='$NicName'"

Then we get the configuration for the NIC by calling it using the index number of the NIC we got from above:

$Nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index=$($Adapter.Index)"

Next, we need to grab the NIC’s IP and subnet mask so we can assign them again later:

$NicIP = $Nic.IpAddress[0]
$NicMask = $Nic.IpSubnet[0]

The, we set the NIC to DHCP,

$Nic.EnableDhcp() | Out-Null

And then back to static, using the IP and mask we retrieved from above:

$Nic.EnableStatic($NicIp,$NicMask) | Out-Null

We can wrap this into a function and call it in our validation scripts.

function Remove-NicGateway	{
<#
.SYNOPSIS
	Removes the default gateway on a specified network interface card (NIC)

.DESCRIPTION
	Removes the default gateway on a specified network interface card (NIC) by first setting the NIC to DHCP, and then setting it back to static and not specifying the gateway - just the IP and subnet mask

.NOTES
  Version      				: 1.0
  Rights Required			: Local admin on server
  										: ExecutionPolicy of RemoteSigned or Unrestricted

	Author       				: Pat Richard, Exchange MVP
	Email/Blog/Twitter	: pat@innervation.com 	https://www.ucunleashed.com @patrichard
	Dedicated Blog			: https://www.ucunleashed.com/152

	Author       				: Serkan Varoglu
	Email/Blog/Twitter	: N/A	http://www.get-mailbox.org	@SRKNVRGL

	Disclaimer   				: You running this script means you won't blame me if this breaks your stuff.
	Info Stolen from 		: 

.EXAMPLE
	Remove-NIcGateway -NicName [name of NIC]

.INPUTS
	None. You cannot pipe objects to this script.

#Requires -Version 2.0
#&gt;
	[cmdletBinding(SupportsShouldProcess = $true)]
	param(
		[parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No NIC name specified")]
		[ValidateNotNullOrEmpty()]
		[string]$NicName
	)
	$Adapter = Get-WmiObject -Class&nbsp;Win32_NetworkAdapter -Filter "NetConnectionID='$NicName'"
	$Nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index=$($Adapter.Index)"
	$NicIP = $Nic.IpAddress[0]
	$NicMask = $Nic.IpSubnet[0]
	Write-Verbose "$NicIP $NicMask"
	$Nic.EnableDhcp() | Out-Null
	Start-Sleep -s 5
	Write-Verbose "Setting $NicName to $NicIP $NicMask"
	$Nic.EnableStatic($NicIp,$NicMask) | Out-Null
} # end function Remove-NicGateway

And call it via:

Remove-NicGateway -NicName [NIC/Team Name]

such as

Remove-NicGateway -NicName "Replication"

Hopefully, this will be useful to you.

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.

Function: Set-DriveLabel – Change the Label of a Drive Via PowerShell

March 6th, 2012 1 comment

Powershell_logo-137x137Description

Here’s a simple function to change the label of a drive.

function Set-DriveLabel	{
	<#
	.SYNOPSIS
	  Sets the label on a drive.

	.DESCRIPTION
	  Sets the label on a drive to a user specified value

	.NOTES
	    Version      			: 1.0
	    Rights Required			: Local admin on server
	    					: ExecutionPolicy of RemoteSigned or Unrestricted
	    Exchange Version			: N/A
            Author     				: Pat Richard, Exchange MVP
            Email/Blog/Twitter	                : pat@innervation.com 	https://www.ucunleashed.com @patrichard
            Dedicated Blog			: https://www.ucunleashed.com/1097
            Disclaimer   			: You running this script means you won't blame me if this breaks your stuff.

	.EXAMPLE
		Set-DriveLabel -DriveLetter "d:" -DriveLabel "Data"

	.INPUTS
		None. You cannot pipe objects to this script.

	#Requires -Version 2.0
	#>
	[cmdletBinding(SupportsShouldProcess = $true)]
	param(
		[parameter(Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No drive letter specified")]
		[string]$DriveLetter,
		[parameter(Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No drive label specified")]
		[string]$DriveLabel
	)
	Write-Host "Setting drive label - drive $DriveLetter"
	$drive = Get-WmiObject -Class Win32_Volume -Filter "DriveLetter = '$DriveLetter'"
	Set-WmiInstance -input $drive -Arguments @{Label="$DriveLabel"} | Out-Null
	If ((Get-WmiObject -Class Win32_Volume -Filter "DriveLetter = '$DriveLetter'").Label -eq $DriveLabel){
		return $true
	}else{
		return $false
	}
} # end function Set-DriveLabel

You would then call it as such:

Set-DriveLabel -DriveLetter [drive] -DriveLabel [label]

such as

Set-DriveLabel -DriveLetter d: -DriveLabel "Data"

Comment based help is available via

Get-Help Set-DriveLabel

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: ,

Programatically Add Heys and Values to edgetransport.exe.config for Exchange 2010

February 22nd, 2012 No comments

Recently, some testing on some new Exchange 2010 hub transport servers yielded some less than expected performance results. Processor utilization was much higher during sustained load testing of message throughput in some dedicated message journal sites.

A colleague worked to determine a solution, and came up with adding two keys and respective values to the EdgeTransport.exe.config file in [Exchange installation folder]\bin. This caused a substantial drop in processor utilization, but caused another problem – how to deploy this solution easily, in a repeatable fashion? We certainly don’t want to have to manually edit dozens of XML files across the production environment.

Our deployment method was entirely scripted, so I set out to find a way to incorporate the fix into the server provisioning scripts. Having not had to deal with editing XML files before, I did a fair amount of searching online, but had trouble with nearly everything I found. Obscure errors, and overly complex code had me just cobbling some things together until it worked. I finally came up with the New-AppSetting function below. It’s lean and mean, but it works.

function New-AppSetting {
	<#
	.SYNOPSIS
	  Adds keys and values to the EdgeTransport.exe.config file for Exchange 2010 	

	.DESCRIPTION
	  Adds user defined keys and values to the EdgeTransport.exe.config file for Exchange 2010 and restarts MSExchangeTransport service 

	.NOTES
	Version      			: 1.0
	Rights Required			: Local admin on server
	    				: ExecutionPolicy of RemoteSigned or Unrestricted
	Exchange Version		: 2010 SP1 UR6
    	Author(s)    			: Pat Richard (pat@innervation.com)
	Dedicated Post			: https://www.ucunleashed.com/1055
	Disclaimer   			: You running this script means you won't blame me if this breaks your stuff.
	Info Stolen from 		:	

	.EXAMPLE
		New-AppSetting -key [key] -value [value]

	.INPUTS
		None. You cannot pipe objects to this script.

	#Requires -Version 2.0
	#>

	[cmdletBinding(SupportsShouldProcess = $true)]
	param(
		[parameter(Position = 0, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No key specified")]
		[string]$key,
		[parameter(Position = 0, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No value specified")]
		[string]$value
	)
	[string]$configfile = $env:ExchangeInstallPath+"bin\EdgeTransport.exe.config"
	if (Test-Path $ConfigFile){
		[xml]$xml = Get-Content $ConfigFile
		[string]$currentDate = (get-date).tostring("MM_dd_yyyy-hh_mm_s")
		[string]$backup = $configfile + "_$currentDate"
		Copy-Item $configfile $backup
		$new = $xml.CreateElement('add')
		$new.SetAttribute('key', $key)
		$new.SetAttribute('value', $value)
		$xml.configuration.appSettings.AppendChild($new) | Out-Null
		$xml.Save($ConfigFile)
	}
	Restart-Service MSExchangeTransport
} # end function New-AppSetting

You call it via:

New-AppSetting -key [key name] -value [value]

such as

 New-AppSetting -key "RecipientThreadLimit" -value "20"

And it will add the key at the bottom of the list in EdgeTransport.exe.config and restart the transport service for the change to take effect. Prior to making the change, it creates a backup copy of EdgeTransport.exe.config for safe keeping.

One caveat – I didn’t have a lot of time to add some error checking or validation. The script does not check to see if the key is already present in the list (in our case, it’s not). So if you run the function multiple times with the same key name, you’ll end up with that key appearing multiple times in EdgeTransport.exe.config. I worked around this quickly in my script by using the following:

if ((Get-Content ($env:ExchangeInstallPath+"bin\edgetransport.exe.config")) -notmatch "RecipientThreadLimit"){
	New-AppSetting -key "RecipientThreadLimit" -value "20"
}

If I get some free cycles, I’ll streamline this a little more. But it works, and we’re able to continue deploying dozens of hub transport servers.

Function: New-BalloonTip – PowerShell Function to Show Balloon Tips

February 21st, 2012 5 comments

Description

Sometimes, we run scripts that may take quite a while to process. Rather than sit idly and watch the script process, we can trigger balloon tips to let us know when it’s done. Something like:

Balloon Tip

Balloon Tip

These are the same type of balloon tips that alert us to outdated or disabled security settings, pending updates, etc.

Windows Update balloon tip

Windows Update balloon tip

This handy little function makes it very easy to use this useful feature. I took the info from PS1 at http://powershell.com/cs/blogs/tips/archive/2011/09/27/displaying-balloon-tip.aspx and put it into a function and optimized it a little. You can specify the icon (none, info, warning, error), the title text, and the tip text.

function New-BalloonTip  {
<#
.SYNOPSIS
  Displays a balloon tip in the lower right corner of the screen.

.DESCRIPTION
  Displays a balloon tip in the lower right corner of the screen. Icon, title, and text can be customized.

.NOTES
  Version                 : 1.3
  Wish List               :
  Rights Required         : Local admin on server
                          : If script is not signed, ExecutionPolicy of RemoteSigned (recommended) or Unrestricted (not recommended)
                          : If script is signed, ExecutionPolicy of AllSigned (recommended), RemoteSigned, 
                            or Unrestricted (not recommended)
  Sched Task Required     : No
  Lync/Skype4B Version    : N/A
  Author/Copyright        : © Pat Richard, Skype for Business MVP - All Rights Reserved
  Email/Blog/Twitter      : pat@innervation.com   https://www.ucunleashed.com @patrichard
  Dedicated Post          : https://www.ucunleashed.com/1038
  Disclaimer              : You running this script means you won't blame me if this breaks your stuff. This script is
                            provided AS IS without warranty of any kind. I disclaim all implied warranties including, 
                            without limitation, any implied warranties of merchantability or of fitness for a particular
                            purpose. The entire risk arising out of the use or performance of the sample scripts and 
                            documentation remains with you. In no event shall I be liable for any damages whatsoever 
                            (including, without limitation, damages for loss of business profits, business interruption,
                            loss of business information, or other pecuniary loss) arising out of the use of or inability
                            to use the script or documentation. 
  Acknowledgements        : 
  Assumptions             : ExecutionPolicy of AllSigned (recommended), RemoteSigned or Unrestricted (not recommended)
  Limitations             : 
  Known issues            : None yet, but I'm sure you'll find some!                        

.LINK
  
Function: New-BalloonTip – PowerShell Function to Show Balloon Tips
.EXAMPLE New-BalloonTip -icon [none|info|warning|error] -title [title text] -text [text] Description ----------- Creates a balloon tip in the lower right corner. .INPUTS This function does support pipeline input. #> #Requires -Version 2.0 [CmdletBinding(SupportsShouldProcess = $true)] param( # Specifies the type of icon shown in the balloon tip [parameter(Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateSet("None", "Info", "Warning", "Error")] [ValidateNotNullOrEmpty()] [string] $Icon = "Info", # Defines the actual text shown in the balloon tip [parameter(Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No text specified!")] [ValidateNotNullOrEmpty()] [string] $Text, # Defines the title of the balloon tip [parameter(Position = 2, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No title specified!")] [ValidateNotNullOrEmpty()] [string] $Title, # Specifies how long to display the balloon tip [parameter(Position = 3, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [ValidatePattern("[0-9]")] [int] $Timeout = 10000 ) PROCESS{ [system.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') | Out-Null # Add-Type -AssemblyName System.Windows.Forms #if (! $script:balloon) { #$script:balloon = New-Object System.Windows.Forms.NotifyIcon $balloon = New-Object System.Windows.Forms.NotifyIcon #} $path = Get-Process -Id $pid | Select-Object -ExpandProperty Path $balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path) $balloon.BalloonTipIcon = $Icon $balloon.BalloonTipText = $Text $balloon.BalloonTipTitle = $Title $balloon.Visible = $true $balloon.ShowBalloonTip($Timeout) $balloon.Dispose() } # end PROCESS } # end function New-BalloonTip

And you can call it by either supplying the parameter names:

New-BalloonTip -icon info -text 'PowerShell script has finished processing' -title 'Completed'

or not:

New-BalloonTip info 'PowerShell script has finished processing' 'Completed'

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: ,

Functions: Get-UACStatus Set-UACStatus – PowerShell Functions for Getting and Setting UAC Status

February 20th, 2012 7 comments

Windows-logo-128x128User Account Control, also known as UAC, was designed to reduce vulnerability by requiring confirmation when system settings are being changed. Some people hate it, some don’t mind it. But most understand it’s intent.

In any case, when deploying servers, it’s key to know what state the UAC settings are in, so that we can script accordingly. Normally, I just set the registry value to whatever I need it to be, using a one-liner such as:

To disable UAC:

Set-ItemProperty -Path HKLM:\Software\Microsoft\Windows\CurrentVersion\policies\system -Name EnableLUA -Value 0

To enable UAC:

Set-ItemProperty -Path HKLM:\Software\Microsoft\Windows\CurrentVersion\policies\system -Name EnableLUA -Value 1

UAC changes how a token is assembled when you log on. If we’re making changes to this, remember that a reboot is required before the new setting takes effect.

But what if we just need to programmatically peek at what UAC is set to, so that we can act accordingly? Well, this handy little function should help:

function Get-UACStatus {
	<#
	.SYNOPSIS
	   	Gets the current status of User Account Control (UAC) on a computer.

	.DESCRIPTION
	    Gets the current status of User Account Control (UAC) on a computer. $true indicates UAC is enabled, $false that it is disabled.

	.NOTES
	    Version      			: 1.0
	    Rights Required			: Local admin on server
	    					: ExecutionPolicy of RemoteSigned or Unrestricted
	    Author(s)    			: Pat Richard (pat@innervation.com)
	    Dedicated Post			: https://www.ucunleashed.com/1026
	    Disclaimer   			: You running this script means you won't blame me if this breaks your stuff.

	.EXAMPLE
		Get-UACStatus

		Description
		-----------
		Returns the status of UAC for the local computer. $true if UAC is enabled, $false if disabled.

	.EXAMPLE
		Get-UACStatus -Computer [computer name]

		Description
		-----------
		Returns the status of UAC for the computer specified via -Computer. $true if UAC is enabled, $false if disabled.

	.LINK
	  
Functions: Get-UACStatus Set-UACStatus – PowerShell Functions for Getting and Setting UAC Status
.INPUTS None. You cannot pipe objects to this script. #Requires -Version 2.0 #> [cmdletBinding(SupportsShouldProcess = $true)] param( [parameter(ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, Mandatory = $false)] [string]$Computer ) [string]$RegistryValue = "EnableLUA" [string]$RegistryPath = "Software\Microsoft\Windows\CurrentVersion\Policies\System" [bool]$UACStatus = $false $OpenRegistry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,$Computer) $Subkey = $OpenRegistry.OpenSubKey($RegistryPath,$false) $Subkey.ToString() | Out-Null $UACStatus = ($Subkey.GetValue($RegistryValue) -eq 1) write-host $Subkey.GetValue($RegistryValue) return $UACStatus } # end function Get-UACStatus

You can call it via

Get-UACStatus

to see the status for the local machine, and

Get-UACStatus -Computer [computer name]

to see the status of a remote machine. Full help is available via

Get-Help Get-UACStatus

And if we need a little function to deal with enabling or disabling, for building into deployment scripts, we have this one, which includes functionality for rebooting:

function Set-UACStatus {
	<#
	.SYNOPSIS
		Enables or disables User Account Control (UAC) on a computer.

	.DESCRIPTION
		Enables or disables User Account Control (UAC) on a computer.

	.NOTES
		Version      			: 1.0
		Rights Required			: Local admin on server
						: ExecutionPolicy of RemoteSigned or Unrestricted
		Author(s)    			: Pat Richard (pat@innervation.com)
		Dedicated Post			: https://www.ucunleashed.com/1026
		Disclaimer   			: You running this script means you won't blame me if this breaks your stuff.

	.EXAMPLE
		Set-UACStatus -Enabled [$true|$false]

		Description
		-----------
		Enables or disables UAC for the local computer.

	.EXAMPLE
		Set-UACStatus -Computer [computer name] -Enabled [$true|$false]

		Description
		-----------
		Enables or disables UAC for the computer specified via -Computer.

	.LINK
	  
Functions: Get-UACStatus Set-UACStatus – PowerShell Functions for Getting and Setting UAC Status
.INPUTS None. You cannot pipe objects to this script. #Requires -Version 2.0 #> param( [cmdletbinding()] [parameter(ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, Mandatory = $false)] [string]$Computer = $env:ComputerName, [parameter(ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, Mandatory = $true)] [bool]$enabled ) [string]$RegistryValue = "EnableLUA" [string]$RegistryPath = "Software\Microsoft\Windows\CurrentVersion\Policies\System" $OpenRegistry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,$Computer) $Subkey = $OpenRegistry.OpenSubKey($RegistryPath,$true) $Subkey.ToString() | Out-Null if ($enabled -eq $true){ $Subkey.SetValue($RegistryValue, 1) }else{ $Subkey.SetValue($RegistryValue, 0) } $UACStatus = $Subkey.GetValue($RegistryValue) $UACStatus $Restart = Read-Host "`nSetting this requires a reboot of $Computer. Would you like to reboot $Computer [y/n]?" if ($Restart -eq "y"){ Restart-Computer $Computer -force Write-Host "Rebooting $Computer" }else{ Write-Host "Please restart $Computer when convenient" } } # end function Set-UACStatus

Call it via

Set-UACStatus -Computer [computer name] -Enabled [$true|$false]

And, like Get-UACStatus, full help is available via

Get-Help Set-UACStatus

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.

Function: Set-ModuleStatus – PowerShell Function for Loading and Verifying Modules

December 27th, 2011 14 comments

PowerShell-logo-128x84Description

Often in my PowerShell scripts, I need to either load a specific module, or verify it’s loaded. Manually, of course, we can use Get-Module, Import-Module, etc. But in automation scripts, we need to programmatically make sure the module is loaded or load it if it’s not. I wrote this function and it’s worked well for me. introducing Get-ModuleStatus:

function Set-ModuleStatus { 
	[CmdletBinding(SupportsShouldProcess = $True)]
	param	(
		[parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No module name specified!")] 
		[ValidateNotNullOrEmpty()]
		[string] $name
	)
	PROCESS{
		# Executes once for each pipeline object
		# the $_ variable represents the current input object		
		if (!(Get-Module -name "$name")) { 
			if (Get-Module -ListAvailable | Where-Object Name -eq "$name") { 
				Import-Module -Name "$name"
				# module was imported
				# return $true
			} else {
				# module was not available
				# return $false
			}
		} else {
			# Write-Output "$_ module already imported"
			# return $true
		} 
	} # end PROCESS
} # end function Set-ModuleStatus

Call it supplying the module name, such as

Set-ModuleStatus Lync

You can use logic such as

if (Set-ModuleStatus Lync){Write-Host "Lync module is loaded"}else{Write-Host "Lync module is NOT loaded" -ForegroundColor red}

Simple and effective. You can also pipe module names to it, such as:

“lync”,”activedirectory” | Set-ModuleStatus

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.

Download

v1.2 – 02-07-2014 – Set-ModuleStatus.v1.2.zip

v1.1 – 09-17-2012 - Set-ModuleStatus.v1.1.zip

v1.0 Get-ModuleStatus.ps1

Categories: PowerShell Tags: ,

Function: New-Password – Creating Passwords with PowerShell

December 26th, 2011 2 comments

Description

When creating new accounts, an admin needs to assign a password. We often then check the box to force a user to change their password when they logon for the first time. Some organizations will use a ‘default’ password for all new accounts. That’s fraught with security implications, and I’ve never recommended it. The downside is that you, as an admin, need to think up a password for each new account. I know how it is – you look around at things on your desk, items on the wall, looking for ideas. Then you have to make sure your super password meets your organizations password requirements, including length and complexity. Well, no more!

Enter New-Password. This function takes one simple input – length. It then spits out a password of said length, using upper and lower case letters, numbers, and punctuation, as well as a phonetic version. If you choose not to use some of the punctuation characters, feel free to just put a ‘#’ in front of that particular line.

function New-Password	{
<#
.SYNOPSIS
  Displays a complex password.

.DESCRIPTION
  Displays a complex password. Output includes password, and phonetic breakdown of the password.

.NOTES
  Version                 : 1.3
  Wish List               :
  Rights Required         : No special rights required
                          : If script is not signed, ExecutionPolicy of RemoteSigned (recommended) or Unrestricted (not recommended)
                          : If script is signed, ExecutionPolicy of AllSigned (recommended), RemoteSigned, 
                            or Unrestricted (not recommended)
  Sched Task Required     : No
  Lync/Skype4B Version    : N/A
  Author/Copyright        : © Pat Richard, Skype for Business MVP - All Rights Reserved
  Email/Blog/Twitter      : pat@innervation.com   https://www.ucunleashed.com @patrichard
  Dedicated Post          : https://www.ucunleashed.com/915
  Disclaimer              : You running this script means you won't blame me if this breaks your stuff. This script is
                            provided AS IS without warranty of any kind. I disclaim all implied warranties including, 
                            without limitation, any implied warranties of merchantability or of fitness for a particular
                            purpose. The entire risk arising out of the use or performance of the sample scripts and 
                            documentation remains with you. In no event shall I be liable for any damages whatsoever 
                            (including, without limitation, damages for loss of business profits, business interruption,
                            loss of business information, or other pecuniary loss) arising out of the use of or inability
                            to use the script or documentation. 
  Acknowledgements        : 
  Assumptions             : ExecutionPolicy of AllSigned (recommended), RemoteSigned or Unrestricted (not recommended)
  Limitations             : 
  Known issues            : None yet, but I'm sure you'll find some!                        

.LINK
  
Function: New-Password – Creating Passwords with PowerShell
.EXAMPLE New-Password -Length <integer> Description ----------- Creates a password of the defined length .EXAMPLE New-Password -Length <integer> -ExcludeSymbols Description ----------- Creates a password of the defined length, but does not utilize the following characters: !$%^-_:;{}<># &@]~ .INPUTS This function does support pipeline input. #> #Requires -Version 3.0 [CmdletBinding(SupportsShouldProcess = $true)] param( #Defines the length of the desired password [Parameter(ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)] [ValidateNotNullOrEmpty()] [ValidatePattern("[0-9]")] [int] $Length = 12, #When specified, only uses alphanumeric characters for the password [Parameter(ValueFromPipeline = $False, ValueFromPipelineByPropertyName = $True)] [switch] $ExcludeSymbols ) PROCESS { $pw = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" if (!$ExcludeSymbols) { $pw += "!$%^-_:;{}<># &@]~" } $password = -join ([Char[]]$pw | Get-Random -count $length) Write-Output "`nPassword: $password`n" ForEach ($character in [char[]]"$password"){ [string]$ThisLetter = $character switch ($ThisLetter) { a {$ThisWord = "alpha"} b {$ThisWord = "bravo"} c {$ThisWord = "charlie"} d {$ThisWord = "delta"} e {$ThisWord = "echo"} f {$ThisWord = "foxtrot"} g {$ThisWord = "golf"} h {$ThisWord = "hotel"} i {$ThisWord = "india"} j {$ThisWord = "juliett"} k {$ThisWord = "kilo"} l {$ThisWord = "lima"} m {$ThisWord = "mike"} n {$ThisWord = "november"} o {$ThisWord = "oscar"} p {$ThisWord = "papa"} q {$ThisWord = "quebec"} r {$ThisWord = "romeo"} s {$ThisWord = "sierra"} t {$ThisWord = "tango"} u {$ThisWord = "uniform"} v {$ThisWord = "victor"} w {$ThisWord = "whiskey"} x {$ThisWord = "xray"} y {$ThisWord = "yankee"} z {$ThisWord = "zulu"} 1 {$ThisWord = "one"} 2 {$ThisWord = "two"} 3 {$ThisWord = "three"} 4 {$ThisWord = "four"} 5 {$ThisWord = "five"} 6 {$ThisWord = "six"} 7 {$ThisWord = "seven"} 8 {$ThisWord = "eight"} 9 {$ThisWord = "nine"} 0 {$ThisWord = "zero"} ! {$ThisWord = "exclamation"} $ {$ThisWord = "dollar"} % {$ThisWord = "percent"} ^ {$ThisWord = "carat"} - {$ThisWord = "hyphen"} _ {$ThisWord = "underscore"} : {$ThisWord = "colon"} `; {$ThisWord = "semicolon"} `{ {$ThisWord = "left-brace"} `} {$ThisWord = "right-brace"} `/ {$ThisWord = "backslash"} `< {$ThisWord = "less-than"} `> {$ThisWord = "greater-than"} `# {$ThisWord = "pound"} `& {$ThisWord = "ampersand"} `@ {$ThisWord = "at"} `] {$ThisWord = "right-bracket"} `~ {$ThisWord = "tilde"} default {$ThisWord = "space"} } if ($ThisLetter -cmatch $ThisLetter.ToUpper()){ $ThisWord = $ThisWord.ToUpper() } $phonetic = $phonetic+" " +$ThisWord } $phonetic = $phonetic.trim() Write-Output "Phonetic: $phonetic" "Password: $password`nPhonetic: $phonetic" | clip Write-Output "`n`nThis information has been sent to the clipboard" } END{ Remove-Variable ThisWord Remove-Variable ThisLetter Remove-Variable Password Remove-Variable Phonetic Remove-Variable Pw } } # end function New-Password

Now, stick that function in your PowerShell profile. Each time you need a new password, use

New-Password -Length [number]

such as

New-Password -Length 12

And you now have a password to use.

12 character password

You can also specify -ExcludeSymbols to return only an alphanumeric password, bypassing the added complexity of using non-alphanumeric symbols.

New-Password -Length 12 -ExcludeSymbols


12 character alphanumeric password

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.