Make sure KB2863058 is installed in the domain’s servers with PowerShell

August 26, 2013

Hello everyone!

Last week, Microsoft has released an update that changes the operating system’s time zone change in certain countries.

In the past, the time zone here in Israel would change in around the month of September. our ministry of the interior decided that it would change the time zone in October 27th, which forced Microsoft to release a new update – the last update was released in December 2012, and that update referred to the time zone shift in September, which isn’t relevant.

I was assigned by the head of IT to write a script that checks if the update is installed on our Windows servers, and log the data in 2 files – the first,  on which server it is installed, and on the second, on which servers it is not installed.

Of course, I could have done it with a killer one liner, but I wrote a script, although quick and dirty, I thought folks could find it helpful, so feel free change it and adjust.

### Make sure AcitveDirectory PowerShell module is installed and available, otherwise,
###use Get-Content with a text file that contains server names.
Import-Module activedirectory
New-Item -Path c:\KB2863058.txt -Type file -Force
New-Item -Path c:\KB2863058_FAILED.txt -Type file -Force
$servers = Get-ADComputer -Filter 'operatingsystem -like "*server*"' | 
select -ExpandProperty name
foreach ($server in $servers) {
if (Test-Connection $server -Quiet -Count 1) {
   try {
    Get-HotFix -Id KB2863058 -ComputerName $server -ErrorAction Stop
    Add-Content -Path C:\KB2863058.txt -Value "$(Get-Date)`t $server`t $($update.InstalledOn)"
   }
   catch {
    "$(Get-Date)`t $server`t`t NO UPDATE" | Out-File c:\KB2863058_FAILED.txt -Append
   }
}
else {
   "$(Get-Date)`t NO CONNECTION`t`t NO CONNECTION" | Out-File c:\KB2863058_FAILED.txt -Append 
}

}

The script creates 2 files. first is C:\KB2863058.txt, which contains all server names where the update was applied. the second, C:\KB2863058_FAILED.txt, contains all server names that wasn’t reached, or whether the update wasn’t applied.
I could use PowerShell Remoting to query the servers in parallel, but WINRM is not enabled in most of them, and writing a workflow is a bit of an overkill for this kind of a task (on my opinion).

Keep on smiling 🙂

Advertisements

Future blog updates!

April 24, 2013

Dear readers!

Very sorry for my blog not being updated regularly, These past few months have been very busy with all source of thing in life.

I’ve got to admit that my daily visitors count is growing steadily, which is very satisfying and I’m very thankful for, but I do need to provide more quality PowerShell content for these new readers. Comparing to other blogs that I follow, the rate that I’m updating my blog is very slow.

I do like to say big thanks for all the readers, looking at the statistics and seeing the numbers grow and people clicking around and finding interest is very gratifying to me.

I’m still learning a lot of new things in PowerShell, things that I found very useful on a daily basis, and I will share those with you. Look out for more frequent blog posts, with content that I hope you will find interesting.

Yours truly,

Nachum


Get only the required parameters when using Get-Help

February 24, 2013

If you type down A cmdlet and forget to include A required parameter (within A parameter set – each parameter set has its own required parameters) than PowerShell will produce an error with the relevant parameter that’s missing.
This trial and error scenario, and carefully reading all of the cmdlet’s help file, is the effective way to get comfortable with A cmdlet.
but sometimes you’ll just want A quick refresher of the required parameters, that’s when I’ll pipe Get-Help -Parameters * to Where-Object:

PS C:\> Get-Help Get-ADUser -Parameter * | where {$_.required -eq “true”}

The output will be the required parameters help content that lives inside the cmdlet’s help XML file.
Again, that’s a little “trick” I use from time to time when I want A quick refresher about the required parameters.
Don’t forget, not all the parameters you see in the output can work together – some cmdlets have more than 1 property sets. In the case of Get-ADUser, you can’t use “-Filter” alongside “-Identity”.

Do you also need to remind yourself from time to time what are the required parameters?

Tell me what you think!


Find Active Directory computer objects by their Operating System

January 15, 2013

Find out if you still have any Windows 2000 objects left in your domain

I was recently asked by a friend how to find Windows 2000 computers with PowerShell.

While its very easy to accomplish with ADUC, he needed a script.

Every computer object in Active Directory has an Operating System attribute (simply called “OperatingSystem”).

All you need to do is to use Get-ADComputer cmdlet and provide an expression for its filter parameter.

PS C:\> Get-ADComputer -Filter ‘OperatingSystem -like “Windows 2000*”‘

Checking \ Setting Remote Desktop Services Profile Settings

December 24, 2012

Check or Set Remote Desktop Services Profile Settings With PowerShell

Many Administrators and Helpdesk teams are assigned with the task of configuring their clients RDP Settings. from the GUI, It is done through the “Remote Desktop Services Profile” tab in the ADUC user settings (that’s in Windows Server 2008 R2. in earlier versions, its called “Terminal Services Profile”)

Like most IT tasks (when it comes to Microsoft’s products), this task can be automated with PowerShell.
Personally, I like to use Microsoft’s ActiveDirectory PowerShell module for all PowerShell AD tasks.

In order to retrieve Remote Desktop settings, the Classic “Get-ADUser -Identity SomeUser -Properties *” wont help us find properties with relevant info, because Get-ADUser can’t get them all.

Another built-in solution is to use the old-fashioned ADSI adapter type. the .NET frameworks wraps the adapter like a PowerShell object. its accessible through the .psbase member set which let us access the objects public members.
Not as friendly as a Cmdlet, but it will give us properties and methods to work with.

The ADSI adapter is operated using LDAP queries (it can also query other LDAP instances than Active Directory), which means I have to use a Distinguished Name (DN) in order to get the user object:

PS C:\> $ADUser = [ADSI]”LDAP://CN=UserName,OU=Users,DC=TestDomain,DC=com”

But I got many OU’s… and typing down DN’s is so V1…

PS C:\> $ADUser = Get-ADUser UserName | select -ExpandProperty disting*
PS C:\> $ADUser = [ADSI]”LDAP://$ADUser”

(Notice that LDAP is all upper-case!)

Next, I query the object received with its InvokeGet() method.
First, I see if the Profile Path attribute is populated:

PS C:\> $ADUser.psbase.InvokeGet(“terminalservicesprofilepath”)
\\TSServer\Profiles\UserName

And make sure that the “Deny this user permissions to log on to Remote Desktop Sessions host server”
is UN-checked (“1” stands for allow, “0” for denied):

$ADUser.psbase.InvokeGet(‘allowlogon’)
1

So I can also check bulks of users:

PS C:\> Get-ADGroupMember Sales_Team | ForEach-Object {
>> Write-Host $_.samaccountname + ” RDP Configuration:”
>> $x = [ADSI]”LDAP://$($_.DistinguishedName)”
>> $x.psbase.invokeget(“terminalservicesprofilepath”)
>> $x.psbase.invokeget(“allowLogon”)
>> }

Thats pretty useful, but how do I configure those attributes? similar to the last example, I use the InvokeSet() method.

PS C:\> $x.psbase.invokeset(“terminalservicesprofilepath”,”\\TSServer\Profiles\UserName”)
PS C:\> $x.psbase.invokeSet(“allowLogon”,1)
PS C:\> $x.setinfo()

Do you find it helpful?
Let me know what you think!
Happy scripting 🙂



Enable PowerShell V2 on Windows 8

November 4, 2012

Enable PowerShell V2 in Windows 8

I’ve been working with Windows 8 for a week or so on my laptop, and I’ve noticed something.
While trying to start a PowerShell V2 host, I get a message that The .NET Framework Version 2 isn’t installed – a requirement for PowerShell V2 to work.

Here is a solution:

Very Important – In order for this to work, you need to assure 2 things:

  1. You need to open an elevated Shell.
  2. You need to open a 64 bit command shell if you’re using a 64 bit Windows OS.

.NET framework version 3.5 is available for installation – as a Windows Feature (which contains all past versions – including version 2) in Windows 8. I know that by using V3’s Get-WindowsOptionalFeature cmdlet, which is part of the DISM PowerShell Module:

PS C:\Windows\system32>; Get-WindowsOptionalFeature -Online | where {$_.FeatureName -Like ‘netfx3’}
Feature Name : NetFx3
State : DisabledWithPayloadRemoved

Now that I know its there, I have to enable that feature (you can also just pipe the former example):

PS C:\Windows\system32>; Enable-WindowsOptionalFeature -Online -FeatureName netfx3Path :
Online : True
Restart Needed : False

installation will take a few minutes. once it’s finished, I can now load a V2 Host:

I can confirm it by checking the $PSVersionTable variable, and its PSVersion property :

PS C:\Windows\system32>; $PSVersionTableName
—- —–
CLRVersion 2.0.50727.6387
BuildVersion 6.1.7600.16385
PSVersion 2.0
WSManStackVersion 2.0
PSCompatibleVersions {1.0, 2.0}
SerializationVersion 1.1.0.1
PSRemotingProtocolVersion 2.1

Set User’s Home Folder That Is Managed With FSRM – PowerShell

October 24, 2012

Managing Home Folders with FSRM

Important! The following article only applies to FSRM Roles that are installed on Windows Server 2003/2008/R2, as 2012 FSRM has it’s own PowerShell module!

In our organization, we got users asking us to increase their Home Folder’s capacity on a daily basis. We manage these home folders on our file servers using the File Server Resource Manager (FSRM) server role.

Everytime you want to set a quota limit that is managed wtih FSRM, you have to do it with the FSRM MMC, and its biggest downside, is that even when you only need to set just one quota limit, you need to wait for all the other data to load, and that can take well more than 8 or so seconds on most occasions – enough time to set quotas for multiple users through a script.

Where I work, we got at least 1000 quotas on each file server, scattered around 8 file server across the country. loading all that data over WAN can sometimes be annoying.

Now when it comes to setting those quotas with powershell, one possibility is to load the Fsrm.FsrmQuotaManager COM Object into the shell and use it to set Quotas. But this COM object doesn’t exists in Windows 7, only on the server itself (Server 2003 / 2008 ) and I don’t want to access the relevant file server with Remote Desktop every time I need set a quota limit… and my security team doesn’t allow me to start PS Sessions to most of our servers..

Using dirquota.exe With PowerShell to Set Home Folders That are Managed with FSRM

Throughout my search for a solution, I found out that Microsoft’s Storage Team supply the dirquota.exe utility, that comes along when you install the FSRM RSAT Tool (in “turn windows features on or off”, select Remote Server Administration Tools > File Services Tools > File Server resource Manager Tools)

I’ve played with it, and like most .exe utilities, it’s not as syntax-friendly and easy to use as a PowerShell Cmdlet. one of the reasons is that you have to type the original path of that folder (D:\Users\James), and that can be a problem, because that path can be different from one file server to another. therefore, it’s easier for me to use a UNC.

So I decided I’ll just write a Cmdlet that will pass its data to the relevent parameters of dirquota.exe.

instead of finding out the true location of the UNC (D:\Users\James. or is it E:\Users\James? errh!) and then use dir quota:

PS C\:> dirquota.exe q m /remote:FileServer /path:D:\Users\James /Limit:1400MB

I will run a PowerShell Cmdlet:

PS C:\> Set-FSRMQuota -User James -Limit 1700

Lets get to Work!

Writing the Script Cmdlet

By understanding how dirquota.exe accpets input, I know 3 things:

  • I need to know the name of the file server that is hosting the home folder.
  • I need to know the home folder’s original path on that server.
  • I’ll need to take this data, and populate dirquota’s appropriate parameters.

Sounds like a classic PowerShell mission…

For the first task, we will use Get-ADUser to store the user information in a variable.

Next, we’ll export the UNC out of the user’s HomeDirectory attribute:

Now I’ll need to extract the Share name and the Server name out of the UNC. I’ll try to minimize the use of string editing. first,

I’ll use Get-Item to extract the shared folder’s name:

PS C:\> $FolderUNC = (Get-Item $UNC).parent | select -ExpandProperty name

and then I’ll just trim the original UNC in two phases:

PS C:\> $ServerUNC ($UNC -Replace “$FolderUNC.*”).Trim(‘\’)

Note that im using “Select -ExpandProperty” (Select is an alias for Select-Object). I do it because I need that object as a type of string, because the original object is the type of ActiveDirectory.Management.ADUser, and it’s value is something that i cant edit, or attach to Get-Item.

Now, We need to find the UNC’s original path on the file server. For this task, I’ll use WMI’s Win32_Share class. I’ll use it on $ServerUNC, because that is the file server that hosts the home folder. I’ll filter the results with Where-Object to try to find a folder that its name matches $FolderUNC:

We’ll extract that path and save it in a variable:


Only thing left, is to populate dirquota’s “/limit:” parameter, which accepts data as a number, followed by a “MB” suffix (for example – “1700MB”). because the final script is accessible like a Cmdlet, it has a variable that accept’s parameter input, with a “param ()” block at the start of the script. We will use this for illustration:

Now we can run direquota.exe and populate its parameters with all the data we collected. this command will live inside the final script:

dirquota.exe q m /remote:$serverUNC /path:$path\$($ad.SamAccountName) /limit:$limit
Quotas modified successfully

Informing us that the “Quotas modified successfully” is very helpful. but i want a final report on the operation I just did! I’ll store all the data that I collected into a custom object that I’ll create using New-Object:

finally, We will put everything we wrote in an Advanced Function construct, so we can use it like we wanted to in the first place – without typing the File Server and the original path, because the file servers and the path’s can be configured and named differently from one server or user to another.

PS C:\> Set-FSRMQuota -User James -Limit 500

This is how the final script looks like.

A link to download from MS TechNet gallery:

Set-FSRMQuota