PoshWSUS V1.1 is available

I just published my latest version of the PoshWSUS module to CodePlex which has some updated code on a few functions and some other bug fixes.  Also, there are 8 new commands that are available with this latest version of the module. The majority of these commands deal with creating and working with the Approval Rules in WSUS that can be set to automatically approve specific types of patches for specific groups. The other functions deal with connecting to the database server that the WSUS database is hosted on and looking at the update classifications in WSUS.

New Commands

  • New-WSUSInstallApprovalRule
    • Used to create a new WSUS Install Approval Rule
  • Set-WSUSInstallApprovalRule
    • Configures an existing Approval Rule. Also allows you to Disable/Enable a rule.
  • Get-WSUSInstallApprovalRules
    • Lists all Approval Rules on WSUS
  • Remove-WSUSInstallApprovalRule
    • Removes a specified Approval Rule
  • Start-WSUSInstallApprovalRule
    • Runs a specified Approval Rule
  • Connect-WSUSDatabaseServer
    • Connects to and lists configuration of SQL Database server used by WSUS
  • Test-WSUSDatabaseServerConnection
    • Presents a True/False along with error when attempting to test connection to Database server from system this command is being ran from.
  • Get-WSUSUpdateClassifications
    • Lists all Update classifications on WSUS server

Examples

Get-WSUSUpdateClassifications

This command was one I thought I already included in V1.0, but as I was working on the Approval commands, it became apparent that this was not the case.  This command is pretty straight forward and gives you all of the update classifications on the WSUS server.

Get-WSUSUpdateClassifications

Capture

Test-WSUSDatabaseServerConnection

Test-WSUSDatabaseServerConnection

Capture

Connect-WSUSDatabaseServer

This command, while using the –Passthru switch, will show you the database server and how it is connecting.  A global variable is also created with the name $wsusdb.

Connect-WSUSDatabaseServer -Passthru

Capture

Viewing the $wsusdb using Get-Member will list out everything that can be done with that database using various methods.  This is a little more beyond what I am going to show you here.  But you can feel free to play with it and see what you get.  If I have more time, I will attempt to dive deeper into it.

Capture

New-WSUSInstallApprovalRule

This command allows you to create a Install Approval Rule in WSUS that will automate the approval process for you by approving specific patches that meet the criteria that you determine and will only apply to whichever groups you pick. This does require some extra steps in getting the group/s, classification/s and categories prior to creating the new rule.

$cat = Get-WSUSUpdateCategories | ? {$_.Title -eq "Windows Server 2008"}
$group = Get-WSUSGroups | ? {$_.Name -eq "Test"}
$class = Get-WSUSUpdateClassifications | ? {$_.Title -eq "Updates"}
New-WSUSInstallApprovalRule -Name "Rule1" -Category $cat -Classification $class -Group $group -Enable

Capture

Capture

Get-WSUSInstallApprovalRules

This command will list all of the Approval Rules on the WSUS server.

Get-WSUSInstallApprovalRules

Capture

Set-WSUSInstallApprovalRule

Much like the New-WSUSInstallApprovalRule, this one may require some prep work prior to actually running the command.  If you are just going to enable/disable the rule, then it is as simple as running the command with the –Enable or –Disable switch.

 

Set-WSUSInstallApprovalRule -Name 'Rule1' -Enable

Capture

Get-WSUSInstallApprovalRule | ? {$_.Name -eq "Rule1"} | Set-WSUSInstallApprovalRule -Disable

Capture

Capture

Besides that, as long as you supply a new group, or new classifications and categories, you can also edit what groups a rule could apply to as well as the classifications and update categories to change on the rule.

$cat = Get-WSUSUpdateCategories | ? {$_.Title -eq "Windows Server 2003"}
$group = Get-WSUSGroups | ? {$_.Name -eq "Test"}
$class = Get-WSUSUpdateClassifications | ? {$_.Title -eq "Updates"}
Set-WSUSInstallApprovalRule -Name "Rule1" -Category $cat -Classification $class -Group $group

Capture

Capture

Start-WSUSInstallApprovalRule

This command will start the approval rule process and automatically approve updates based on the requirements of a specified Approval Rule. Just make sure the rule is enabled prior to running this command.

Start-WSUSInstallApprovalRule

Remove-WSUSInstallApprovalRule

As this command states, this will remove a Approval Rule from WSUS.

Remove-WSUSInstallApprovalRule -Name 'Rule1'

Capture

 

Code

The downloads for this updated Module are available from the following locations:

Script Repository

CodePlex

Please use either the comments here, codeplex or the script repository to report any bugs that are found. Also, any features or things of that nature that you would like to see added can be posted in those areas as well. 

Posted in Modules, powershell, WSUS | Tagged , , , | 8 Comments

Use PowerShell to remove local profiles

A couple of days ago at work, I was asked a question concerning whether a specific one-liner of code would work remotely. That one-liner was (Get-WMIObject Win32_UserProfile | ? {$_.localpath –like “*username).Delete()} I told him that, yes, in fact it would work.  After this, I began to think of a way to make a script that will allow a help desk person, desktop support admin or a server admin to run the script and have it prompt for a machine, rather local or remote to make a connection to and then present a list of user profiles and the option to remove a specified profile.

Overall, it is a fairly simplistic script with with a couple Do/Until loops for the selection processes and some Try/Catch  error checking (which in opinion, should always be included in any script that runs on PowerShell V2). I also make use of System.Management.Automation.Host.ChoiceDescription  class to present a choice at the end of the script on whether the user wishes to quit the script or re-scan and delete another profile.

OS Compatibility

A big gotcha with this script is that while it can be ran from any machine with PowerShell v2, it can only be ran against a client using Vista and above or a server running Windows 2008 and above.  Any other OS’s lower than this do not have the WMI class require for this to work and will fail.

Example

In this example, I have my profile (boe) on my laptop and another account (testuser) that I logged into to create the local profile folder.

Capture

I now call my script which asks for a computername, in which I type in the name and am then presented with 2 profiles, boe and testuser along with the option to quit the profile removal script. You will notice that it starts at 0, which is the beginning index of the array of user profiles.

Capture

I now select the testprofile to remove it.  Since it is labeled 0, I type in 0 and proceed to remove the profile. After a few seconds (your time will vary depending on the size of the profile), I get a confirmation that the profile has been successfully deleted.  There is then another prompt to either continue removing profiles or exit the script.

Capture

As you can see, the folder is now gone.

Capture

Really, that is all there is to it. This can be ran against a remote machine as well and it uses the Test-Connection cmdlet to verify the network access prior to making the WMI connection.

If you try to run this against a server that has an unsupported OS, then the script will throw an error and close.

Capture

Code

The script is available from the following locations:

Script Repository

PoshCode

<#   
.SYNOPSIS   
    Interactive menu that allows a user to connect to a local or remote computer and remove a local profile. 
.DESCRIPTION 
    Presents an interactive menu for user to first make a connection to a remote or local machine.  After making connection to the machine,  
    the user is presented with all of the local profiles and then is asked to make a selection of which profile to delete. This is only valid 
    on Windows Vista OS and above for clients and Windows 2008 and above for server OS.    
.NOTES   
    Name: Remove-LocalProfile 
    Author: Boe Prox 
    DateCreated: 26JAN2011       
.LINK   
    https://boeprox.wordpress.com
    http://msdn.microsoft.com/en-us/library/ee886409%28v=vs.85%29.aspx 
.EXAMPLE  
Remove-LocalProfile 
 
Description 
----------- 
Presents a text based menu for the user to interactively remove a local profile on local or remote machine.    
#>  
 
#Prompt for a computer to connect to 
$computer = Read-Host "Please enter a computer name" 
#Test network connection before making connection 
If ($computer -ne $Env:Computername) { 
    If (!(Test-Connection -comp $computer -count 1 -quiet)) { 
        Write-Warning "$computer is not accessible, please try a different computer or verify it is powered on." 
        Break 
        } 
    } 
Try {     
    #Verify that the OS Version is 6.0 and above, otherwise the script will fail 
    If ((Get-WmiObject -ComputerName $computer Win32_OperatingSystem -ea stop).Version -lt 6.0) { 
        Write-Warning "The Operating System of the computer is not supported.`nClient: Vista and above`nServer: Windows 2008 and above." 
        Break 
        } 
    } 
Catch { 
    Write-Warning "$($error[0])" 
    Break 
    }     
Do {     
#Gather all of the user profiles on computer 
Try { 
    [array]$users = Get-WmiObject -ComputerName $computer Win32_UserProfile -filter "LocalPath Like 'C:\\Users\\%'" -ea stop 
    } 
Catch { 
    Write-Warning "$($error[0]) " 
    Break 
    }     
#Cache the number of users 
$num_users = $users.count 
 
Write-Host -ForegroundColor Green "User profiles on $($computer):" 
 
    #Begin iterating through all of the accounts to display 
    For ($i=0;$i -lt $num_users; $i++) { 
        Write-Host -ForegroundColor Green "$($i): $(($users[$i].localpath).replace('C:\Users\',''))" 
        } 
    Write-Host -ForegroundColor Green "q: Quit" 
    #Prompt for user to select a profile to remove from computer 
    Do {     
        $account = Read-Host "Select a number to delete local profile or 'q' to quit" 
        #Find out if user selected to quit, otherwise answer is an integer 
        If ($account -NotLike "q*") { 
            $account = $account -as [int] 
            } 
        }         
    #Ensure that the selection is a number and within the valid range 
    Until (($account -lt $num_users -AND $account -match "\d") -OR $account -Like "q*") 
    If ($account -Like "q*") { 
        Break 
        } 
    Write-Host -ForegroundColor Yellow "Deleting profile: $(($users[$account].localpath).replace('C:\Users\',''))" 
    #Remove the local profile 
    ($users[$account]).Delete() 
    Write-Host -ForegroundColor Green "Profile:  $(($users[$account].localpath).replace('C:\Users\','')) has been deleted" 
 
    #Configure yes choice 
    $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes","Remove another profile." 
 
    #Configure no choice 
    $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No","Quit profile removal" 
 
    #Determine Values for Choice 
    $choice = [System.Management.Automation.Host.ChoiceDescription[]] @($yes,$no) 
 
    #Determine Default Selection 
    [int]$default = 0 
 
    #Present choice option to user 
    $userchoice = $host.ui.PromptforChoice("","Remove Another Profile?",$choice,$default) 
    } 
#If user selects No, then quit the script     
Until ($userchoice -eq 1)
Posted in powershell, scripts | Tagged , , | 26 Comments

WSUS Administrator Module to CodePlex as PoshWSUS

You heard it, I have finally set up a project over at CodePlex for my WSUS module.  The link to the project is here: http://poshwsus.codeplex.com/

Feel free to follow the project, add suggestions and note any issues/bugs that you find while using this module and I will do my best to knock them out.

Also, I am looking to publish my next version 1.1 of the module which will include 8 new commands and has some updated code as well on previous commands.

Posted in Modules, News, powershell, WSUS | Tagged , , , , | Leave a comment

Setting IIS log locations with PowerShell

In my previous post, I showed you how to query for the location of IIS log files using ADSI and connecting to remote systems.  In this post, I will show you some code that will allow you to set the log location for each website in IIS or all of the depending on your preference.

This script came about from a forum post in the Windows PowerShell forum in which a user wanted to change the IIS log locations. Basically you can specify 1 or more computers to run the script advanced function against. Also is the capability to specify a website as opposed to the default of all websites to change the location. The last parameter you need to provide is the new location of where the logs will go.  Using this along with my Get-IISLogLocation will allow you to easily locate and change the log locations.

PS C:\Users\boe> Get-IISLogLocation -computer dc1

Server                                  WebSite                                 LogLocation
——                                  ——-                                 ———–
dc1                                     {Default Web Site}                      {C:\temp}

PS C:\Users\boe> Set-IISLogLocation -computer dc1 -website “Default Web Site” -logdir “D:\logs”
Default Web Site: Log location set to D:\logs
PS C:\Users\boe> Get-IISLogLocation -computer dc1

Server                                  WebSite                                 LogLocation
——                                  ——-                                 ———–
dc1                                     {Default Web Site}                      {D:\logs}

This script also supports the use of –whatif and –confirm

Capture

You can also find this script out on the Script Repository and out at PoshCode.

Function Set-IISLogLocation {
<#
.SYNOPSIS
    This command will allow you to set the IIS log location on a server or multiple servers.
.DESCRIPTION
    This command will allow you to set the IIS log location on a server or multiple servers.
.PARAMETER computer
    Name of computer to set log location on
.PARAMETER logdir
    Location to set IIS logs to write to
.PARAMETER website
    Name of website to change the log location.
.NOTES
    Name: Set-IISLogLocation
    Author: Boe Prox
    DateCreated: 20Aug2010  

.LINK
    https://boeprox.wordpress.com
.EXAMPLE
    Set-IISLogLocation -computer <server> -logdir "D:\logs" 

Description
-----------
This command will change the IIS log locations for each website on the server.
.EXAMPLE
    Set-IISLogLocation -computer <server> -logdir "D:\logs" -website "Default Web Site" 

Description
-----------
This command will change the IIS log locations for only the Default Web Site on a server. 

#>
[cmdletbinding(
    SupportsShouldProcess = $True,
    DefaultParameterSetName = 'default',
    ConfirmImpact = 'low'
)]
param(
    [Parameter(
        Mandatory = $False,
        ParameterSetName = '',
        ValueFromPipeline = $True)]
        [string]$computer,
    [Parameter(
        Mandatory = $False,
        ParameterSetName = '',
        ValueFromPipeline = $False)]
        [string]$logdir,
    [Parameter(
        Mandatory = $False,
        ParameterSetName = 'site',
        ValueFromPipeline = $False)]
        [string]$website
)
Process {
    ForEach ($c in $Computer) { 

            If (Test-Connection -comp $c -count 1) { 

                $sites = [adsi]"IIS://$c/W3SVC"
                $children = $sites.children
                ForEach ($child in $children) {
                    Switch ($pscmdlet.ParameterSetName) {
                       "default" {
                                If ($child.KeyType -eq "IIsWebServer") {
                                If ($pscmdlet.ShouldProcess($($child.servercomment))) {
                                    $child.Put("LogFileDirectory",$logdir)
                                    $child.SetInfo()
                                    Write-Host -fore Green "$($child.servercomment): Log location set to $logdir"
                                    }
                                }
                            }
                        "site" {
                                If ($child.KeyType -eq "IIsWebServer" -AND $child.servercomment -eq $website) {
                                If ($pscmdlet.ShouldProcess($($child.servercomment))) {
                                    $child.Put("LogFileDirectory",$logdir)
                                    $child.SetInfo()
                                    Write-Host -fore Green "$($child.servercomment): Log location set to $logdir"
                                    }
                                }
                            }
                        }
                    }
            }
        }
    }
}
Posted in powershell, scripts | Tagged , , , | Leave a comment

Locating IIS Logs with PowerShell

It has been a while since I last posted here at my blog. Work, holidays that required travelling across a state, getting married and a honeymoon in Cozumel, Mexico have kept me plenty busy during the last month and a half.  But I am back and looking forward to a new post and a new year of learning and working with PowerShell!

This post is going to deal with finding the location of your IIS logs using an advanced function I wrote in response to a Windows PowerShell forum post last year where a user wanted to find a way to list out all of the locations of the log file for each site. While I did not use the IIS PowerShell snap-in to solve this issue, I was able to solve it using the ADSI type and connecting to IIS that way.  This is just one way of working with IIS and other ways include WMI, a snap-in and the IIS provider. Here is a link that deals with using both ADSI and WMI for IIS.

I chose to work with ADSI as it appeared to be the easiest way for me to accomplish what I wanted to do.  The function is pretty simple and just creates a custom object to store the data I need. In this case, the server name, website name and log file location.  This function can be run against 1 or more servers and it will return back the information required, which could be exported out to a CSV file if needed.

One thing I ran into was the script would not return back anything when ran from a Windows 7 workstations.  Turns out I did not have everything loaded that needed to be running thanks to this site.

Here is an example of me running it against a server of mine.

Untitled

Function Get-IISLogLocation { 
<#   
.SYNOPSIS   
    This function can be ran against a server or multiple servers to locate 
    the log file location for each web site configured in IIS. 
.DESCRIPTION 
    This function can be ran against a server or multiple servers to locate 
    the log file location for each web site configured in IIS.     
.PARAMETER computer 
    Name of computer to query log file location. 
.NOTES   
    Name: Get-IISLogLocation 
    Author: Boe Prox 
    DateCreated: 11Aug2010  
          
.LINK   
    https://boeprox.wordpress.com 
.EXAMPLE   
Get-IISLogLocation -computer 'server1' 
 
Description 
----------- 
This command will list the IIS log location for each website configured on 'Server1' 
           
#>  
[cmdletbinding( 
    SupportsShouldProcess = $True, 
    DefaultParameterSetName = 'computer', 
    ConfirmImpact = 'low' 
)] 
param( 
    [Parameter( 
        Mandatory = $False, 
        ParameterSetName = 'computer', 
        ValueFromPipeline = $True)] 
        [string[]]$computer       
) 
Begin { 
    $report = @() 
    } 
Process { 
    ForEach ($c in $Computer) { 
            Write-Verbose "Checking connection on $($c)"
 
            If (Test-Connection -comp $c -count 1) { 
                
                Write-Verbose "Making IIS connection to $($c)" 
                $sites = [adsi]"IIS://$c/W3SVC" 
                $children = $sites.children 
                ForEach ($child in $children) { 
                    Write-Verbose "Checking $child.servercomment" 
                    If ($child.KeyType -eq "IIsWebServer") { 
                        Write-Verbose "Found site"
                        $temp = "" | Select Server, WebSite, LogLocation 
                        $temp.Server = $c 
                        $temp.WebSite = $child.ServerComment 
                        $temp.LogLocation = $child.LogFileDirectory                            
                        $report += $temp  
                        }                                                             
                    } 
            }                 
        }  
    } 
End { 
    $report 
    } 
}
Posted in powershell, scripts | Tagged , , , | 13 Comments