Archive

Posts Tagged ‘PowerShell’

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: New-LocalExchangeConnection – Ensure Your PowerShell Script is Connected to Exchange 2010

December 28th, 2011 11 comments

Description

When writing scripts that execute commands on an Exchange server, for Exchange 2010, it’s important to ensure that you’re running within a session connected to an Exchange server, and that all Exchange cmdlets are available. In Exchange 2007, we could load the Exchange snapins. But 2010 doesn’t use snapins. Some people would say that you can simply load the modules, but loading the modules bypasses RBAC, and is thus, not recommended. Mike Pfeiffer wrote a great article Managing Exchange 2010 with Remote PowerShell that sheds some light. It’s worth a read.

A solution around this is to run a PowerShell script that comes built into Exchange 2010. This makes available the Connect-ExchangeServer cmdlet, which will connect via remote PowerShell to Exchange. We can specify a server, or let the -auto option connect to the best server via autodiscover. New-LocalExchangeConnection is a function I wrote to connect:

function New-LocalExchangeConnection	{ 
	[cmdletBinding(SupportsShouldProcess = $true)]
	param(
	)
	Write-Verbose "Checking for Exchange Management Shell"
	$Sessions = Get-PSSession | Where-Object {$_.ConfigurationName -eq "Microsoft.Exchange"}
	if (!($Sessions)){
		if (Test-Path "$env:ExchangeInstallPath\bin\RemoteExchange.ps1"){
			Write-Verbose "Exchange Management Shell not found - Loading..."
			. "$env:ExchangeInstallPath\bin\RemoteExchange.ps1"
			Write-Verbose "Exchange Management Shell loaded"
			Write-Verbose "Connecting to Exchange server"
			Connect-ExchangeServer -auto
			if (Get-PSSession | Where-Object {$_.ConfigurationName -eq "Microsoft.Exchange"}){
				Write-Verbose "Connected to Exchange Server"
			}else{
				Write-Host "An error has occurred" -ForegroundColor red
			}
		}else{
			Write-Warning "Exchange Management Shell is not available on this computer"
		}
	}else{
		Write-Verbose "Exchange Management Shell already loaded"
	}
} # end function New-LocalExchangeConnection

Calling this within your script will make ensuring that your script is running with access to Exchange cmdlets much simpler.

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.

Functions: Get-LocalAdminGroupMembership and Set-LocalAdminGroupMembership – Local Admin Group Membership on Remote Machines

December 22nd, 2011 No comments

PowerShell-logo-128x84While writing some PowerShell scripts to automate the installation of Exchange on over 100 servers, I needed to set and then verify that a group (in this case, “Exchange Trusted Subsystem”) was a member of the local admins group on some remote servers.

We start with Get-LocalAdminGroupMembership. This function merely checks the local admins group on a remote server to see if the group to be added is already a member. If it is, it returns $true, if not, $false. We need to pass it two variables: $ComputerName, and $Member. We don’t need to run this function. It’s called from the second function.

function Get-LocalAdminGroupMembership	{
	[CmdletBinding()]
	Param(
		[Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
		$ComputerName = ".",
		[Parameter(Position=1, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
		$Member
	)
	if($ComputerName -eq "."){$ComputerName = (get-WmiObject win32_computersystem).Name}
	$computer = [ADSI]("WinNT://" + $ComputerName + ",computer")
	$Group = $computer.psbase.children.find("Administrators")
	$members= $Group.psbase.invoke("Members") | % {$_.GetType().InvokeMember("Name", "GetProperty", $null, $_, $null)}
	if ($members -match $member){return $true}else{return $false}
} # end function Get-LocalAdminGroupMembership

 

The second function does all the heavy lifting.

function Set-LocalAdminGroupMembership {
	[CmdletBinding()]
	Param(
		[Parameter(Position=0, Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
		[string]$ComputerName = ".",
		[Parameter(Position=1, Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
		[string]$Member,
		[Parameter(Position=2, Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
		[string]$Domain = $env:USERDNSDOMAIN
	)

	Process{
		if (!(Get-LocalAdminGroupMembership -ComputerName "$ComputerName" -Member "$Member")){
			if($ComputerName -eq "."){$ComputerName = $env:ComputerName.ToUpper()}    

			if($Domain){
  			$adsi = [ADSI]"WinNT://$ComputerName/administrators,group"
    		$adsi.Add("WinNT://$Domain/$Member,group")
			}else{
	  		Write-Host "Not connected to a domain." -ForegroundColor "red"
			}
		} else {
			Write-Host "`"$Account`" is already a local admin on $ComputerName" -ForegroundColor yellow
		}
		Get-LocalAdminGroupMembership -ComputerComputer "$ComputerName" -Member "$Member"
	}# Process
} # end function Set-LocalAdminGroupMembership

We call Set-LocalAdminGroupMembership and pass it the same parameters, $ComputerName and $Member

Set-LocalAdminGroupMembership -ComputerName mycomputer -Member "Exchange Trusted Subsystem"

The function will add the group to the local admins group, and then do a Get-LocalAdminGroupMembership for that same group and dump the results to the screen.

Function: New-Pause – Pausing PowerShell Scripts

December 21st, 2011 No comments

Yesterday, I wrote about a sleep function to cause a predetermined delay in a script. Today, I give you a short function, New-Pause. New-Pause stops a script and waits for the user to press a key before continuing.

function New-Pause {
 Write-Host "Press any key to continue" -ForegroundColor green
 $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
} # end function New-Pause

We can add some flexibility into it by allowing for the function to be called with alternative values for the text color and the text itself.

function New-Pause {
  [CmdletBinding(SupportsShouldProcess, SupportsPaging, HelpUri = 'https://ucunleashed.com/885')]
  param(
    # Text that is displayed as the prompt when paused.
    [Parameter(ValueFromPipelineByPropertyName)]
    [ValidateNotNullOrEmpty()]
    $PausePrompt = 'Press any key to continue',
    
    # Color of the prompt.
    [Parameter(ValueFromPipelineByPropertyName)]
    [ValidateNotNullOrEmpty()]
    [ValidateSet('Black', 'DarkMagenta', 'DarkRed', 'DarkBlue', 'DarkGreen', 'DarkCyan', 'DarkYellow', 'Red', 'Blue', 'Green', 'Cyan', 'Magenta', 'Yellow', 'DarkGray', 'Gray', 'White')]
    $PauseColor = 'Green'
  )
  Write-Host $PausePrompt -ForegroundColor $PauseColor
  $null = $host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
  Write-Host 'Continuing...'
} # end function New-Pause

Call the function using

New-Pause
New-Pause

New-Pause

Once any key is pressed, your script can continue.

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

Function: New-Sleep – When You Need a Delay

December 20th, 2011 6 comments

Description

On a recent project, I needed some PowerShell scripts to wait for a few seconds just to ensure that some other processes were finished and I wasn’t issuing too many commands to some Exchange servers too quickly. I came up with this little function:

function New-Sleep {
	[cmdletbinding()]
	param(
		[parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No time specified")]
		[int]$s
	)
	for ($i=1; $i -lt $s; $i++) {
	[int]$TimeLeft=$s-$i
	Write-Progress -Activity "Waiting $s seconds..." -PercentComplete (100/$s*$i) -CurrentOperation "$TimeLeft seconds left ($i elapsed)" -Status "Please wait"
	Start-Sleep -Seconds 1
	}
	Write-Progress -Completed $true -Status "Please wait"
} # end function New-Sleep

Call the function like this:

New-Sleep -s 60

Where the value of $s is the number of seconds you want to sleep. The display tells you how long your sleeping for, how much time is left, and how much time has elapsed.

New-Sleep

New-Sleep

Download the function below.

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 New-Sleep.ps1

Categories: PowerShell Tags: ,

Lync Posters, Templates, and Cheat Sheets

October 13th, 2011 No comments

Posters

Microsoft Lync Server 2010 Protocol Workloads Poster

This poster shows each workload in Microsoft Lync Server 2010 communications software, describing relationships, dependencies, flow of information, and certificate requirements.

http://go.microsoft.com/fwlink/?LinkId=204599

Visio templates

Lync Server 2010

This stencil provides over 125 shapes to help you create a visual presentation of your Lync Server architecture.

http://www.microsoft.com/downloads/en/details.aspx?FamilyID=65b5a396-2c87-445d-be23-d324727d19cb

Office Communications Server 2007 and 2007 R2

The Office Communications Server 2007 and 2007 R2 Visio stencils contain icons for Office Communications Server 2007 and 2007 R2 server roles and components.

http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=9194

Cheat Sheets

Lync Server 2010 PowerShell Cheat Sheet

A quick reference card for PowerShell use with Lync Server 2010.

http://www.powergui.org/entry.jspa?externalID=3091

Microsoft Lync 2010 Quick Reference Cards

This zipped file contains the quick reference cards for Microsoft Lync 2010. They are all in Microsoft Word, and can be edited as needed. The download contains the following Quick Reference Cards, which are also available separately:

http://www.microsoft.com/download/en/details.aspx?id=2324

One Liners: Setting Recovery Option to ‘restart’ for Lync/Skype4B Services

October 5th, 2011 3 comments

Lync 2013 logo 128x128A client wanted to configure the recovery options for services in Lync to help reduce downtime if/when a service stops. This was no big deal for me, except there are a dozen Lync servers, some of which have quite a few Lync services. I set out to make this easier than manually changing each service’s recovery options.

Service recovery options allow you to define what Windows should do if the service fails. The options are “Take No Action” (the default), “Restart the Service”, “Run a Program”, and “Restart the Computer”. These options can be defined for the first, second, and subsequent service failures. Additional parameters include how long to wait before resetting the failure counter and how long to wait after the service fails before performing the configured failure option. More complex options include running another program:

Default service recovery options before running sc.exe

Default service recovery options before running sc.exe

Unfortunately, PowerShell’s Set-Service doesn’t have a parameter for setting failure options, so we must rely on the command line sc.exe. Sc.exe can be used to create, modify, and delete services. We’ll use this to set our failure options to restart the services. Note: you must use “sc.exe” and not just “sc”, since in PowerShell, “sc” is an alias for Set-Content. The format is

sc.exe [service name] failure reset= [integer] actions= [actions]

Reset is measured in seconds. We’ll use 86400, which is a full 24 hours. Actions are specified as action/wait time in milliseconds. So “restart/5000” means to wait 5000 milliseconds (5 seconds), and then restart the service. The same action will be applied to the first, second, and subsequent service failure.

We’ll use Get-CimInstance with the Win32_Service classname to grab a list of all of the services, piping that to match descriptions that include ‘Lync’ or ‘Skype for Business’, and start modes that are “automatic”. The finished one liner command looks like this:

$services = Get-CimInstance -ClassName 'Win32_Service' | Where-Object {$_.description -imatch 'Lync|Skype for Business' -and $_.StartMode -eq 'Auto'}; foreach ($service in $services){sc.exe failure $service.name reset= 86400 actions= restart/5000}
Recovery options changed

Recovery options changed (click to enlarge)

When we view the properties of the service again, we see that the failure options are set to restart the service, and to reset the counter after 1 day. Since the restart option is only 5 seconds, the “Restart service after” field shows 0 minutes:

Service recovery options after running sc.exe

Service recovery options after running sc.exe

You can also specify different actions for each of the failure instances by adding more actions. For instance, let’s say you want to restart the service for the first and second failures, and reboot the server on subsequent failures. Simply combine the actions together, separating them with a slash, such as:

$services = Get-CimInstance -ClassName 'Win32_Service' | Where-Object {$_.description -imatch 'Lync|Skype for Business' -and $_.StartMode -eq 'Auto'}; foreach ($service in $services){sc.exe failure $service.name reset= 86400 actions= restart/5000/restart/5000/reboot/5000}

It might be wise to not set all of the failure instances to taking action, to prevent the server from getting stuck in a loop of taking action when a service is having serious issues. To only set the first two options, just use a double slash for the third, such as:

$services = Get-CimInstance -ClassName 'Win32_Service' | Where-Object {$_.description -imatch 'Lync|Skype for Business' -and $_.StartMode -eq 'Auto'}; foreach ($service in $services){sc.exe failure $service.name reset= 86400 actions= restart/5000/restart/5000//}

Obviously, a good monitoring solution such as System Center Operations Manager (SCOM) should be used to track and alert when services stop, and when other more serious issues arise. You don’t want to get into a scenario where a service is constantly stopping and being restarted without knowing.

Script: New-HandBrakeConversion.ps1 – Convert Entire Folders of Files to .mp4 With HandBrake

October 4th, 2011 19 comments

I watch at LOT of movies. Since I’m generally away from home at least 200 days a year, I spend a lot of time in airports, on airplanes, in hotels, etc. When I work from home, I watch movies and TV shows as well. My iPad and my 5TB iTunes library keep me entertained.

Many of the videos I have start in something other than the .mp4/.m4v format that iTunes requires. Either it’s something I’ve downloaded, something someone sent me, training (CBT) videos, or something pulled from my HD video camera’s hard drive. The files usually are either .avi or .mkv.

There are plenty of utilities out there that will convert video files from one format to another. Some of them are free, and some cost a few bucks. By far the best, most flexible utility I’ve found is the popular HandBrake. HandBrake has many options that let you get down “in the weeds” with every setting conceivable for converting videos. It has a popular queuing feature that lets you add several files to the queue, and HandBrake will process them, one at a time. Processing time depends on the source file size and format, as well as the destination format. And, it’s FREE.

Since I am away from my monster desktop machine so much, I put it’s i7 processor’s idle time to good use by having it process videos, saving them as .mp4 videos. But manually adding a bunch of videos to HandBrake’s queue can take a while. Plus, since I’m not around when the processing is taking place, I don’t need the fancy GUI from HandBrake. When HandBrake is installed, a CLI version is also automatically installed So I created a PowerShell script that will use the CLI version, take a source folder, and process every video in that directory that doesn’t have a corresponding .mp4 file of the same name. That way, if the script stops and you need to restart it, it won’t re-process video’s it’s already converted. It will only attempt to convert files with .avi, mkv, .ogm, and .wmv extensions, but only the first two, .avi, and .mkv, have been extensively tested.

The script will automatically detect if/where HandBrake is installed, so there is nothing really to configure. Run the script with no switches, and you’ll be prompted for the source folder that contains the videos to be converted:

.\New-HandBrakeConversion.ps1

Or, you can specify the source folder and avoid the prompt:

.\New-HandBrakeConversion.ps1 -dir "c:\path\to\files"

For those of you who are hardcore HandBrake users, the configuration settings I use are the following:

-e x264 -b 1500 -a 1 -E faac -B 160 -R Auto -6 dpl2 -f mp4 -m -2 -T -x ref=2:bframes=2:me=umh -n eng

Let me know if you have any questions or comments.

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.

There is no installation routine for this script. It’s meant to be manually run.

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 New-HandBrakeConversion.v1.3.zip

Changelog

See the changelog for this script for all version information

Categories: PowerShell Tags: ,