Advertisements

Archive for the ‘Administration’ Category

Powershell Script to Locate Windows Services Running as Domain users

Ever had to change a domain administrator’s password and had the sinking feeling that some bozo had setup a Windows service to run as that user.   If you only have a couple servers it isn’t that big a deal to check each manually, but if you have a lot it can be a problem.  I’ve seen a lot of admins just use the scream test to figure out what broke, but sometimes it isn’t obvious until the server is rebooted.  We run into this situation frequently as we take over new clients.

Recently we had to make a change for a customer with 50+ Windows servers and I knew the account had been used for services. I just didn’t know where.  So I built the below powershell script.  I definitely owe a few people props as I used a number of different websites to figure out the WMI piece. Unfortunately, it has been too long since I remember who.  But the next best thing is to put this script out there for other to use.  So I have posted the script and a readme file to GitHub (a new experience for me, but way better than how I published my scripts previously).

https://github.com/Deadtired78/Find-DomainUserServices.ps1/

Hope this helps out.  This is provided “as-is” and while I’ve used in several environments I can’t guarantee it will work everywhere.  Feel free to leave respectful comments.

Advertisements

Remote Desktop Services “Drain mode” PowerShell script

If you’ve ever had to put a large number of 2008+ Windows Terminal/Remote Desktop servers in “drain mode” using the gui admin tool, you know it can be slow and tedious.  Faced with doing this on a Saturday night for about 30 servers I decided to make life a little quicker and easier by building a powershell script.   While my long term goal is to figure out how to drain an entire farm, for now I’m pretty satisfied to be able to do it from PowerShell pretty quickly.

There are two scripts.  Drain-RDserver.ps1 and Undrain-RDserver.ps1. Both require a single parameter “-RDserver” followed by the server name.  Drain changes the “User logon mode” to “Allow reconnections, but prevent new logons.” This could be changed to the “Allow reconnections, but prevent new logons until the server is restarted” by modifying the script.   Undrain puts the server back in “Allow all connections” mode.

Big thanks to SourceDaddy’s article which got me started on the right path. (http://sourcedaddy.com/windows-7/preparing-server-maintenance.html)

Here is the code:


###Drain-RDServer
# Input computer name
param (
[string]$RDServer = $(throw "-RDserver is required")
)
$RDSH = Get-WmiObject -Class "Win32_TerminalServiceSetting" -Namespace "root\CIMV2\terminalservices" -ComputerName $RDServerdra -Authentication PacketPrivacy -Impersonation Impersonate
$RDSH.SessionBrokerDrainMode=1
$RDSH.put() > $null
Write-Host "$RDServer is set to:"
switch ($RDSH.SessionBrokerDrainMode)
{
0 {"Allow all connections."}
1 {"Allow incoming reconnections but prohibit new connections."}
2 {"Allow incoming reconnections but until reboot prohibit new connections."}
default {"The user logon state cannot be determined."}
}


###Undrain-RDServer
# Input computer name
param (
[string]$RDServer = $(throw "-RDserver is required")
)
$RDSH = Get-WmiObject -Class "Win32_TerminalServiceSetting" -Namespace "root\CIMV2\terminalservices" -ComputerName $RDServer -Authentication PacketPrivacy -Impersonation Impersonate
$RDSH.SessionBrokerDrainMode=0
$RDSH.put() > $null
Write-Host "$RDServer is set to:"
switch ($RDSH.SessionBrokerDrainMode)
{
0 {"Allow all connections."}
1 {"Allow incoming reconnections but prohibit new connections."}
2 {"Allow incoming reconnections but until reboot prohibit new connections."}
default {"The user logon state cannot be determined."}
}

And here is a link to the scripts in a zip file.

Office 365 PowerShell Script to Set PasswordNeverExpires for All Members of Group

I had a need to set all members of a group so that their Office 365 (aka Microsoft Online) passwords never expire.  Didn’t take too long but I though it was worth sharing.  I also added output to show the setting was changed.  This could certainly be prettier but it is what it is.

Pre-Reqs

  • This requires you to have the Office 365 Powershell cmdlets installed, which also required the Online Services Sign-in Agent to work. See this article for instructions.
  • You need admin credentials to your Office 365 account.
  • The script references the ObjectID of the Office 365 Group whose members you wish to change.  To get this you need to connect to Office 365 and use the Get-MsolGroup command. Below is a code snippet showing how.
import-module MSOnline
Connect-MsolService
Get-MsolGroup

Output will look something like below.

Script

The below would need to be saved as a .ps1 file.  The Object ID (shown in red #’s below) would need to be changed to match that of the desired group

import-module MSOnline
Connect-MsolService
### Get All the Members of the Group
$agents=Get-MsolGroupMember -GroupObjectId  ########-####-####-####-############
### Set PasswordNeverExpires to true for all members of the group.
Foreach ($agent in $agents ) {
Set-MsolUser -ObjectID $agent.ObjectID -PasswordNeverExpires $true
$postChangeAgent = Get-MsolUser -ObjectID $agent.ObjectID
Write-Host “User: ” $postChangeAgent.UserPrincipalName “PasswordNeverExpires:” $postChangeAgent.PasswordNeverExpires
}

Note: The line beginning with “Write Host” wraps. The end of that line in your script is the $postChangeAgent.PasswordNeverExpires

Cudos and References

Thanks to JoshT_MSFT @ the Office365 Technical Blog for the following article which pointed me in the correct direction.

http://community.office365.com/en-us/b/office_365_technical_blog/archive/2011/11/01/how-to-disable-password-policy-settings-in-bpos-and-office-365-with-powershell-grid-user-post.aspx

Exchange 2010 Missing Server Configuration in EMC

Just worked on a test(luckily) Exchange 2010 server with a customer.  When they opened the Exchange Management Console, the Server Configuration was missing and they couldn’t change the properties of any the mailboxes. When they opened the mailbox properties they saw these little lock symbols all over the place.

When they ran the command “Get-Mailbox” in the Exchange Management Shell, they only saw a single mailbox.

So we tried all sorts of things. Then they mentioned the installed Outlook on the server and set it up to access a mailbox. Just happened to be the   I tried deleting the mail profile, uninstalling Outlook, logging off and back in, no dice.  Then I found out that Windows caches credentials and you have to clear those out using the below procedure:

  1. Open a command prompt using “Run as Administrator”
  2. Run the command “control keymgr.dll”
  3. Click “Back up vault” and follow the prompts to back everything up.
  4. Find and remove all credentials that have to do with Exchange or the user setup for Outlook.

After that everything returned to normal.

So if you want Outlook on an Exchange server use OWA.

Set Owner with PowerShell: “The security identifier is not allowed to be the owner of this object”

I’ve written several PowerShell scripts to help customers adjust permissions to their directory structures when migrating from other file servers(Linux/Samba, Novell OES/Netware, etc).  Part of these scripts includes assigning ownership for the user.  While this tends to take a long time quotas and file reporting are worthless if the administrator that copied everything is assigned as the owner.

Recently I tried to adapt one of these scripts for a customer, but when I ran it it failed with the error: “The security identifier is not allowed to be the owner of this object”

A quick internet search found lots of people saying basically this can’t be done with PowerShell.  What!!! I know for a fact these scripts had worked before.  What’s the deal?   After a lot of testing and beating my head against the wall I figure out I was trying to do something different.  Previously I had run my scripts against the UNC path (eg. \\servername\share\directory), but this time I was trying to run it on a local directory using the drive path (E:\Share\Directory).

Could it be that simple? Yes.  I ran the command again using the UNC path and the script worked as it did before.

Here is an example script to set the owner of a directory or file to test the above:

function pathPrompt {

$tempPath = $null
$tempPath = Read-Host ‘Please enter the path of thedirectory (e.g. “\\file\vol1\users\example”‘
return $tempPath
}

$username=”exampleuser”
$domain=”domain”
$ID = new-object System.Security.Principal.NTAccount($domain, $username)

$path = pathPrompt

write-host $path

$acl = get-acl $path
$acl.SetOwner($ID)
set-acl -path $path -aclObject $acl

Save the above to a file with a .PS1 extension, change the $username and $domain variables, and run it (make sure you set-executionpolicy to unrestricted and PowerShell as administrator). It will prompt for a path. It will then write the path to powershell and then set the owner if it can.

Below is an example of running it against a local path and a UNC path.

VBScript to create a My Documents Variable

I was recreating a login script for a client that mapped a drive to the location of their redirected My Documents.  Because they were in the middle of a migration the My Documents could be in a different spot depending on if a user had been migrated to a new environment or not. So I needed to be able to query the current location of the My Docs, much like the %userprofile% shows the path to the current profile.

Below is a chunk of VBScript I cobbled together from a variety of sources including ActiveXperts that reads the appropriate registry key value of the user that runs the script.  This chunk just outputs the path to the command line but the myDocsPath variable could also be used to map a drive.

(Please note that the line that starts “Set oReg=GetObject….” and the line below it need to be a single line)

—-Copy Everything Below—–

const HKEY_CURRENT_USER = &H80000001
const HKEY_LOCAL_MACHINE = &H80000002
strComputer = "."
Set StdOut = WScript.StdOut
 
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer &
 "\root\default:StdRegProv")

strKeyPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
strValueName = "Personal"
oReg.GetExpandedStringValue HKEY_CURRENT_USER,strKeyPath,strValueName,myDocsPath
StdOut.WriteLine "Current My Docs path is: " & myDocsPath

 —-Copy Everything Above—–

Creating Lists of Installed Applications

Frequently while performing network assessments I need to assemble a list of all the programs installed on servers. Going to Add/Remove Programs and writing it down is a tedious process.  Installing applications like Belarc Advisor is a bit more intrusive then I want to be on another companies servers.  After some research today I found two solutions that work well:

For XP and Server 2003

http://www.billsway.com/vbspage/ShowScript.asp?tgt=txtfiles/InstalledPrograms.txt

The above contains the contents of a vbscript. You copy the contents into a text file and save it with a .vbs extension.  You can then double-click it. It will prompt you for a computer name or IP address. When it finishes running it generates a file that contains a list of all the programs installed.  It seems to work great with Windows XP and 2003, but only returns a partial list for Windows 2008. 

 For Vista, Windows 7, Server 2008 and 2008 R2

http://www.intowindows.com/how-to-get-list-of-installed-apps-in-vistawindows-7-without-any-software/

This link shows how to generate the list using wmi commands. It says it is for vista and windows 7, but seems to work on Server 2008 just fine. Unlike the vbscript, this must be run directly on the computer in question.

 Conclusion

Both these methods seem to work well, but they do generate files on the system that need to be copied off to be useful.  If you are using them on someone elses computers I would advise you get explicit permission before using these tool. 

Unrelated but also helpful.

If your assessment involves Dell servers, you might want to get the service tags for the servers.  Older Dells tend to put this sticker in inconvenient locations. Luckily you can query the servers for the tag using this handy vbscript.

http://lazynetworkadmin.com/content/view/13/6/

Advertisements