Thursday, October 27, 2011

Finding all file shares on the network

I adapted this script from Michel Steveman's post on printer inventory.

#Purpose: get all file shares and output to Excel

#Create array of servers to retrieve information from by reading masterservers.txt. Could also plug in an AD query here.
$servers= get-content masterservers.txt

#create new Excel WorkBook
$Excel = new-Object -comobject Excel.Application
$Excel.visible = $True
$Excel = $Excel.Workbooks.Add()
$Sheet = $Excel.Worksheets.Item(1)
$Sheet.Cells.Item(1,1) = "Server Name"
$Sheet.Cells.Item(1,2) = "Share Name"
$Sheet.Cells.Item(1,3) = "Share Path"
$intRow = 2
$WorkBook = $Sheet.UsedRange
$WorkBook.Font.Bold = $True

#Get File Share Information and write to Excel
ForEach ($server in $servers)
{
$Shares = Get-WmiObject -Class win32_share -ComputerName $server | where-object {$_.type -eq 0}
foreach ($Share in $Shares)
{
$Sheet.Cells.Item($intRow, 1) = $Server
$Sheet.Cells.Item($intRow, 2) = $Share.Name
$Sheet.Cells.Item($intRow, 3) = $Share.Path
$intRow = $intRow + 1
}
}

$WorkBook.EntireColumn.AutoFit()
$intRow = $intRow + 1
$Sheet.Cells.Item($intRow,1).Font.Bold = $True

Wednesday, October 26, 2011

PowerShell - Output File Share Info to Excel

Need to audit file shares on your network? Here's a quick and easy PowerShell script that will gather all the share names and paths. Note that you need to run this from a computer that has Microsoft Excel installed.

masterservers.txt is a file containing all the servers you want to run the script against. As always, you could also feed an AD query into the $servers array instead of pulling from a file.

#get all file shares and output to Excel

#Set Server Name
$servers= get-content masterservers.txt

#create new Excel WorkBook
$Excel = new-Object -comobject Excel.Application
$Excel.visible = $True
$Excel = $Excel.Workbooks.Add()
$Sheet = $Excel.Worksheets.Item(1)
$Sheet.Cells.Item(1,1) = "Server Name"
$Sheet.Cells.Item(1,2) = "Share Name"
$Sheet.Cells.Item(1,3) = "Share Path"
$intRow = 2
$WorkBook = $Sheet.UsedRange
$WorkBook.Font.Bold = $True

#Get File Share Information
ForEach ($server in $servers)
{
$Shares = Get-WmiObject -Class win32_share -ComputerName $server | where-object {$_.type -eq 0}
foreach ($Share in $Shares)
{
$Sheet.Cells.Item($intRow, 1) = $Server
$Sheet.Cells.Item($intRow, 2) = $Share.Name
$Sheet.Cells.Item($intRow, 3) = $Share.Path
$intRow = $intRow + 1
}
}

$WorkBook.EntireColumn.AutoFit()
$intRow = $intRow + 1
$Sheet.Cells.Item($intRow,1).Font.Bold = $True

Thursday, October 20, 2011

Powershell for Server Inventory

Here are a few snippets I have built to pull inventory information

To gather information where each request will only have one result per machine (doesn't work for things like disk or processor where there can be multiple values for one machine)

#computers.txt should be a list of computers to gather information from. You could also build an AD query instead if you want.
get-Content computers.txt | foreach {
$os=Get-WmiObject -class Win32_OperatingSystem -ComputerName $_
$sys=Get-WmiObject -Class win32_Computersystem -ComputerName $_
$bios=Get-WmiObject -Class win32_Bios -ComputerName $_
$net=Get-WmiObject -Class win32_networkadapterconfiguration -ComputerName $_
$disk=Get-WmiObject -Class win32_logicaldisk
$IP=[System.Net.Dns]::GetHostAddresses($_)| select-object ipaddresstostring

#create a new object so that we can output our data to CSV neatly
#This script returns computer name, OS, memory, vendor, model, domai, serial number, and service tag
new-Object psobject -Property @{
Computername=$_.toUpper()
OperatingSystem=$os.Caption
TotalPhysMemMB=($sys.TotalPhysicalMemory)/1MB -as [int]
Vendor=$sys.Manufacturer
Model=$sys.model
Domain=$sys.domainget
SerialNumber=$os.serialnumber
ServiceTag=$bios.SerialNumber
}| convertto-csv -notypeinfo -outvariable OutData
$outData[1..($outdata.count -1)]|foreach-object {add-content -value $_ -Path OSInfo.csv}
}

This one checks the ping status of each machine in a list of machines. If it is able to ping, it writes that value to a CSV file. If you took out the where-object, you could just have it return the server name and the ping status value instead.

get-content tcmis.txt | ForEach{Get-WmiObject win32_pingstatus -Filter "Address='$_'" | Where-object {$_.statuscode -eq 0} |select-object address, statuscode} | export-csv -notypeinfo exist.csv

Once you have your list of machines that exist, this script can get all the hard drive freespace and size information. It only pulls from non-removable drives (drive type 3)

#Exist.CSV contains a list of computer names. Find all non-removable drive types and export the information to a csv file

Get-content exist.csv | Foreach {Get-WmiObject -Class win32_logicaldisk -ComputerName $_ | where-object {$_.drivetype -eq 3} | select-object systemname, deviceID, FreeSpace, Size}| export-csv diskinfo.csv -notypeinfo

Count Number of Messages sent to Distribution Group

I created this script to tell me how many messages had been sent to each of a list of distribution groups in the last 30 days. It's really useful if you are trying to find groups that aren't used often for cleanup purposes.

#Get all transport servers so we can search across all of them
$hubs=get-TransportServer

#where test.txt contains a list of email addresses
$groups=get-content "C:\MessageTrackingRobin\test.txt"

#For each email address in test.txt, count how many messages were sent to it between the start and end dates, then output that information into count.txt in comma delimited format
foreach ($group in $groups){
$count = ($hubs| get-messagetrackinglog -start "09/19/2011 12:00AM" -End "10/20/2011 11:59PM" -recipients $group)
$output=$group + "," + $count.count
add-content count.txt $output
}

Changing SIP address on multiple users

There are many reasons to change multiple users' SIP domain.  Maybe you acquired a company and are bringing them online with their existing domain name.  Maybe a branch office is planning to do business under a new domain.

Adding a new SIP domain is simple enough in the Topology Builder, and when creating new users it is easy to select the new SIP domain, but when it's existing users converting to the new domain, it’s a lot of clicking in the Lync Control Panel, so I found a nice easy way to do this.

In this example, I have two SIP domain's, contoso.com, and Contoso's new doing business as SIP domain of nwtraders.com.   The entire Boston office is switching over to this, so I am able to select based on Registrar pool, but you can also filter by OU, or any other attributes the users share.

$userscope = Get-CsUser | where { $_.RegistrarPool -eq "boston.contoso.com" }
foreach ($item in $userscope)
    {
        $oldAddress = $item.SipAddress
        $newAddress = $oldAddress -replace "@contoso.com", "@nwtraders.com"
        Set-CsUser -Identity $item.Identity -SipAddress $newAddress
    }


Tuesday, August 30, 2011

Super quick way to Windows Update on a TMG server!

Found this blog article today, it might be old news if you were familiar with ISA or TMG 2010, which I am not, so it was super helpful.


Thanks Richard!

Wednesday, June 29, 2011

Lync 2010 Director and Pool Resiliency settings

You might have noticed the pool resiliency settings in your Topology builder, and I recently was tasked with insuring that clients attaching to the director are offered a primary and secondary registrar.

I did some research and found two great blog articles that you should read regarding Lync and pool resiliency:
So here we see my resiliency settings for our US pool:










And here our resiliency topology settings for our EU pool:


The checkbox for "Enable Failover and Failback" is not very well documented, however I found the best documentation of these settings is in the Set-CsService Technet article.
If I point a Lync client manually at my Director Pool, and take a sipstack trace from the server they hit, I can see only one Contact: line:












Here's the Get-CsUserPoolInfo for this user:





So with this configuration I was hoping to see two servers in the sip trace, one for ee01 and one for corp14ukpool, but this won't happen until you check the boxes above for Enable Failover and Failback. Not sure why this needs to be checked to enable. This leads me to believe selecting a resiliency pool alone does nothing?

Two ways to address this:

  1. Check the boxes in your Topology and republish
  2. Set via Lync powershell cmdlet Set-CsRegistrar as found here - you can confirm your settings are in place with Get-CsService -Registrar
Once this is completed, your SIP trace on your director should show multiple connections:

Tuesday, May 17, 2011

“The user profile service failed the logon. User profile can not be loaded.” logging on to Exchange server

I had this issue a while ago at a customer whose admin account was not allowing him to log on to the Exchange server.  The exact error was:



“The user profile service failed the logon. User profile can not be loaded.”


After reviewing the event logs, I found an error:
"Windows cannot copy file C:\Users\Default\AppData\Local\Microsoft\Exchange Server\V14\CmdletSqmData2292_100.sqm to location C:\Users\a-rnavarro\AppData\Local\Microsoft\Exchange Server\V14\CmdletSqmData2292_100.sqm. This error may be caused by network problems or insufficient security rights.

DETAIL - Access is denied."

The fix was that the Exchange .sqm file had incorrect permissions and was causing this event log on attempted logon;  I set that file path to inherited permissions, and then was able to log on.

Monday, April 11, 2011

How to roll back a Lync Phone Edition to an Office Communicator Phone Edition

I have to admit – this doesn’t sound like a process that would be utilized very often, however there is a good scenario where there is a need to downgrade your device’s code. Imagine someone buying a device that was already patched to Lync code, but was purchased with the intent to use it in an OCS 2007 or R2 environment. 
I was given a Polycom CX700 Lync Edition phone – one that had Lync RTM Phone Edition on it and was then patched to the Lync 2010 CU1 bits. So at best, a paperclip reset would only roll back to the Lync RTM edition.



Furthermore, the Lync RTM edition cannot be used to sign into an OCS environment, so you are left with a phone that needs an older version and not many documented ways to update it.

Unfortunately, this process requires that you have administrative access to a Lync 2010 environment. I would recommend this be a lab environment of course.

You need to get the Lync environment to a point where the device can be used on it. There is a ton of information out there on this, but the short list is:
  • NTP server in place and _ntp._udp.domain.com record in place.
  • Certificate server in place, published to AD and able to issue certs via HTTP/HTTPS.
  • Automatic sign in DNS in place
    • _sip._tcp.domain.com
    • _sip._tls.domain.com
    • _sipinternal._tcp.domain.com
    • _sipinternal._tls.domain.com
    • sip.domain.com
    • sipinternal.domain.com
  • ucupdates.domain.com and ucupdates-R2.domain.com DNS in place, and represented on the Update server’s SSL certificate for updates to occur.  (ucupdates was for OCS 2007 - ucupdates-R2 is used my OCS 2007 R2 and Lync 2010)
Basically – confirm your device can sign into the Lync 2010 organization first. For a great read and a LOT of good info on troubleshooting updates, check Jeff Schertz’s blog on Updating Lync Phone Edition Devices. Once your device is working with Lync 2010 Server, the rollback process is pretty simple. The process of rolling back the version is done using the Device Update service within Lync 2010.
  1. Download the version of UCUpdates.exe that is relevant to your device type and version. I made heavy use of Jeff Schertz’s blog entry here to get the right one. For me, it was the OC 2007 R2 version for the CX700.
  2. On your Lync 2010 server, import the OCPE (OC Phone Edition) into your Lync Device Updates using:
    import-CsDeviceUpdate -Identity service:Webserver:Lyncpoolserver.domain.com -FileName c:\temp\OCPE 2007R2\UcUpdates.cab
  3. On the Lync 2010 Control Panel, confirm that your updates show up and are the correct version. 3.5.6907.222 is the matching version from KB2466291.
  4. DO NOT APPROVE THE UPDATE – DOING THIS WILL APPLY IT TO ALL DEVICES AND UNDESIRABLE AFFECTS!

  5. Under test devices create a new test device, entering the MAC address or serial number of the device you are attempting to revert versions on. This is available under Advanced->System Information from the device.
  6. Reset the device, sign into it, reboot again and walk away for about 15 minutes. It needs to be completely idle to run the update.


After this time passes, the device is able to download the ‘update,’ install it, and reboot.

If you have issues with this, it is likely something with your update server configuration – check the tips in the blog linked earlier on troubleshooting – the W3SVC logs generated here can be very helpful.

The IP address changes in the screenshots are because in the first screen I was on an OCS domain, the second on a Lync 2010 environment.

Monday, February 28, 2011

Redirecting Exchange 2010 OWA from http to https

In Exchange 2007, http can be redirected to https using the URL Redirect method

In Exchange 2010 this doesn't work in most situations because port 80 is required to be open on the localhost address in order for the Exchange Management Console to work properly. In fact if you try to use the URL Redirect method, both Exchange PowerShell and the EMC will start throwing an initialization error. So the solution is to use custom error pages to redirect requests.

Brien M. Posey's article gives a really good explanation of how to create the custom error page for error 403.4 to perform the redirection from port 80 to port 443.

Having port 80 open to the internet is still not very good or secure for Exchange servers and I would encourage moving away from that practice. But if you have an absolute requirement for OWA to be accessible via an http URL, this is a quick and easy way to redirect traffic.

Lync 2010 - Upgrading to RTM and Web Components failing to install.

We accidentally waited too long to update our RC to RTM, and our Front End service was failing to start this morning.

Thankfully, I found this blog entry that Mike Stacy wrote on how to migrate fro m RC to RTM fairly painlessly.
http://mikestacy.typepad.com/mike-stacys-blog/2010/11/upgrading-from-the-release-candidate-of-lync-to-rtm-completely-unsupported.html

And everything worked as expected until I got the below error:
Error: Error returned while installing WebComponents.msi(Feature_WebComponents_CommonFiles,Feature_WebComponent_AddressBook,Feature_WebComponent_AuthFramework,Feature_WebComponent_AdminUI,Feature_WebComponent_CertProv,Feature_WebComponent_DataMCUWeb,Feature_WebComponent_DevUpdate,Feature_WebComponent_DialinPage,Feature_WebComponent_GroupExpansion,Feature_WebComponent_JoinLauncher,Feature_WebComponent_LocationInfo,Feature_WebComponent_MeetingMCUWeb,Feature_WebComponent_OcsPowershell,Feature_WebComponent_Rgs,Feature_WebComponent_ReachWeb,Feature_WebComponent_WebTicket), code 1603. Please consult log at C:\Users\clehradmin\AppData\Local\Temp\Add-WebComponents.msi-Feature_WebComponents_CommonFiles,Feature_WebComponent_Addres~-[2011_02_28][10_26_37].log

Checking in that Web Components log file, I found:
MSI (s) (4C!74) [10:32:06:364]: Product: Microsoft Lync Server 2010, Web Components Server -- Error 29024. Error 0x80004005 (Unspecified error) occurred while executing command 'C:\Windows\system32\inetsrv\appcmd.exe'. For more details, check log file 'C:\Users\CLEHRA~1\AppData\Local\Temp\LCSSetup_Commands.log'.

Checking the LCSSetup_Commands.log, I found this:
Filename: \\?\C:\Windows\system32\inetsrv\config\applicationHost.config
Line Number: 428
Description: Cannot add duplicate collection entry of type 'add' with unique key attribute 'name' set to 'OCSAuthHelperModule'

I edited the ApplicationHost.config, removing the below line for that Module, and was able to then reinstall!

This got me past that issue. Hope this helps someone else.

Thursday, February 17, 2011

Unknown 500 Autodiscover and RPC errors when publishing Exchange 2010 on a non-default web site

Typically, when I am implementing Exchange for a customer, I try to make the configuration as simple as possible.  Sometimes this is not always possible, unfortunately.   This particular customer had an AD FQDN that was a three letter domain name, ending in .com, that they did not own on the Internet, therefor the chances of getting a 3rd party trusted SSL certificate issued for that domain name was not possible.

Below is a diagram of the intended design and configuration of the environment (for simplicity in this post, this is a single server environment, running MBX, CAS, and HT roles on a Windows 2008 R2 Enterprise OS with Exchange 2010 Standard SP1 RU2.

So in IIS, I configured the "External Web Site" to listen explicitly on .14, and the Default listens on .13.
The default web site is protected with an internal CA, and the external with a Digicert UCC certificate.


Once this was configured, I then essentially got Exchange to use it, recreating each vDir:
  • New-AutodiscoverVirtualDirectory  -Website "External" -externalURL "https://mail.company.com/Autodiscover/autodiscover.xml
  • New-EcpVirtualDirectory  -Website "External" -externalURL "https://mail.company.com/ecp"
  • New-WebServicesVirtualDirectory  -Website "External" -externalURL "https://mail.company.com/ews/Exchange.asmx"
  • New-OWAVirtualDirectory -Website "External" -externalURL "https://mail.company.com/owa"
  • New-OABVirtualDirectory  -Website "External" -externalURL "https://mail.company.com/OAB"
  • New-ActivesyncVirtualDirectory  -Website "External" -externalURL "https://mail.company.com/Microsoft-Server-Activesync/"
Finally - the trickiest one is the RPC and RPCWithCert vdir's - I have blogged on that before here and the process still works. So at this point, your IIS console should look like this:


If you notice I removed the Autodiscover vdir on the default web site, it was because LAN users will use SCP and AD to autodiscover.  But otherwise, I have all Exchange vdir's duplicated.

Once this was complete, I had a network engineer create a NAT for me, and an ACL for TCP/443 to my Exchange 2010 CAS server.  I tied the mail.company.com DNS name to the IP of that NAT entry.  Of course, a CNAME for autodiscover.company.com was also created, and my Digicert SSL cert has this name on it as a Subject Alternate Name (SAN)

Then, it was time to head over to the ExRCA tool for some CAS testing!

Unfortunately, I was immediately confronted with odd errors while autodiscovering:
ExRCA is attempting to retrieve an XML Autodiscover response from URL https://autodiscover.company.com/AutoDiscover/AutoDiscover.xml for user [email protected].  ExRCA failed to obtain an Autodiscover XML response.
An HTTP 500 response was returned from Unknown.

From Outlook 2010: 
Autodiscover to https://autodiscover.company.com/autodiscover/autodiscover.xmI Failed (0x80004005)

Running test-OutlookConnectivity against the External Site got this clue: 
Test-OutlookConnectivity:  An unexpected exception occurred while pinging RpcProxy. The most common reason for this occurring is that the IIS DefaultAppPool isn't running. Exception: The remote server returned an error: (500) Internal Server Error.

From the W3SVC2 IIS logs (specific to External site) 
2011-02-15 20:32:57 191.168.1.14 POST /AutoDiscover/AutoDiscover.xml - 443 - xx.xxx.xx.xx Microsoft+Office/12.0+(TestExchangeConnectivity.com) 500 0 0 281 
2011-02-15 20:32:57 191.168.1.14 POST /AutoDiscover/AutoDiscover.xml - 443 - xx.xxx.xx.xx Microsoft+Office/12.0+(TestExchangeConnectivity.com) 500 0 0 78 

Checking the application event log, I found this: 
Log Name:      Application
Source:        System.ServiceModel 3.0.0.0
Date:          2/15/2011 2:38:14 PM
Event ID:      3
Task Category: WebHost
Level:         Error
Keywords:      Classic
User:          SYSTEM
Computer:      Exchange.corp.tld.com
Description: WebHost failed to process a request.  Sender Information: System.ServiceModel.ServiceHostingEnvironment+HostingManager/35104124  Exception: System.ServiceModel.ServiceActivationException: The service '/Autodiscover/AutoDiscover.xml' cannot be activated due to an exception during compilation.  The exception message is: Could not find a base address that matches scheme http for the endpoint with binding CustomBinding. Registered base address schemes are [https].. --->
System.InvalidOperationException: Could not find a base address that matches scheme http for the endpoint with binding CustomBinding. Registered base address schemes are [https].

Process Name: w3wp
Process ID: 5828

 Very Weird.  But the application event log gave the biggest hint with this:
Could not find a base address that matches scheme http for the endpoint with binding CustomBinding. Registered base address schemes are [https]."  

The fix, after a long time researching and trying different things…
Add an http listener for port 80 to the "External" Site. 

I have no idea why this works.  But it does.  That IP does not have port 80 open on the firewall, and while it is working, the IIS logs do NOT show any port 80 traffic coming into it, but without port 80 listening on the site, there are 500 unknown errors on the ExRCA for autodiscover as well the the RPC virtual directories if performing a manually configured test (bypassing autodiscover)


I am not sure if this is a bug, or a known configuration requirement, but I was unable to find any documentation from MSFT on this.

Monday, February 14, 2011

Server Service - Error 2: The system cannot find the file specified

Had a customer with a brand new Windows 2008 R2 server VM that started representing the error shown below.

Error 2: The system cannot find the file specified


I spent some time trying different authentication methods for the service, and trying to confirm versions of srv.sys, all seemed to be correct and OK with the server, and it was patched and up to date as well.

I stumbled upon this thread talking about solving a similar issue:

User m_a_tt's post is what lead me to resolve this issue. 

I checked the "dependencies" of the service on my server:

Compared to another server with the same patch level:

So I browsed into the registry to get the multi-string data that represents these two dependencies:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\LanmanServer


And then added them to my "broken" server's registry.

Rebooted, and all was working again.  After some further digging, I found out that this was indeed manually configured this way by a co-worker who was following instructions from an HP Lefthand SAN installation.  The exact line in their documentation was:

sc lanmanserver depend= MSiSCSI

Future note if you implement storage - this seems to replace existing entries entirely.  The command below would be more appropriate:

sc lanmanserver depend=SamSS/Srv/MSiSCSI

Hope this helps some people searching.  I will post this article in the thread previously mentioned as well.